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
25 changes: 19 additions & 6 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -15065,6 +15065,7 @@ CreateTable CreateTable(boolean isUsingOrReplace):
ColDataType ofType = null;
Table parent;
List<Table> parents = new ArrayList<Table>();
ObjectNames typeName;
boolean withData;
}
{
Expand All @@ -15085,19 +15086,23 @@ CreateTable CreateTable(boolean isUsingOrReplace):
[ LOOKAHEAD(2) tableColumn=TimeTravelAfterAlias() { likeTable.setTimeTravel(tableColumn); } ]
{ createTable.setCloneTable(likeTable); likeTable = null; }
]
[ <K_OF> ofType=ColDataType() { createTable.setOfType(ofType); } ]
[ <K_OF> typeName=RelObjectNames() {
ofType = new ColDataType();
ofType.setDataType(typeName.getNames());
createTable.setOfType(ofType);
} ]
[ LOOKAHEAD(2) <K_PARTITION> <K_OF> partitionOfTable=Table()
{ createTable.setPartitionOf(partitionOfTable); } ]
[ LOOKAHEAD(2) (
LOOKAHEAD("(" ")") "(" ")" { createTable.setTableElements(tableElements); }
|
LOOKAHEAD(3) (
LOOKAHEAD("(" RelObjectName() ("," RelObjectName())* ")") (
"(" tableColumn=RelObjectName() { columns.add(tableColumn); } ("," tableColumn=RelObjectName() { columns.add(tableColumn); } )* ")"
)
|
(
"(" element=CreateTableElement(ofType != null) { tableElements.add(element); }
( LOOKAHEAD(2) "," element=CreateTableElement(ofType != null)
"(" element=CreateTableElement(ofType != null || partitionOfTable != null) { tableElements.add(element); }
( LOOKAHEAD(2) "," element=CreateTableElement(ofType != null || partitionOfTable != null)
{ tableElements.add(element); }
)*
[ LOOKAHEAD({ Dialect.SQLSERVER.name().equals(getAsString(Feature.dialect))
Expand Down Expand Up @@ -15144,8 +15149,16 @@ CreateTable CreateTable(boolean isUsingOrReplace):
createTable.setCreateOptionsStrings(createOptions);
if (typedTableOptions.size() > 0)
createTable.setTableOptions(typedTableOptions);
if (columns.size() > 0)
createTable.setColumns(columns);
if (!columns.isEmpty()) {
if (ofType != null || partitionOfTable != null) {
for (String name : columns) {
tableElements.add(new ColumnDefinition().withColumnName(name));
}
createTable.setTableElements(tableElements);
} else {
createTable.setColumns(columns);
}
}
return createTable;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*-
* #%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.create;

import static org.junit.jupiter.api.Assertions.*;
import java.util.ArrayList;
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.ColumnDefinition;
import net.sf.jsqlparser.statement.create.table.ColumnOption;
import net.sf.jsqlparser.statement.create.table.CreateTable;
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 PostgreSqlTableColumnOverridesTest {
@ParameterizedTest
@ValueSource(strings = {"row_type", "public.row_type", "\"Type.Schema\".\"Row.Type\""})
void keepsTypeNameSeparateFromFirstColumn(String type) throws JSQLParserException {
for (String withOptions : new String[] {"", " WITH OPTIONS"}) {
CreateTable table = parse("CREATE TABLE t OF " + type + " (a" + withOptions
+ " DEFAULT 7 NOT NULL, b, CHECK (a > 0))");
assertEquals(type, table.getOfType().getDataType());
assertNull(table.getOfType().getArgumentsStringList());
assertEquals(2, table.getColumnDefinitions().size());
ColumnDefinition first = table.getColumnDefinitions().get(0);
assertNull(first.getColDataType());
assertEquals(!withOptions.isEmpty(), first.isWithOptions());
assertEquals("b", table.getColumnDefinitions().get(1).getColumnName());
assertEquals(ColumnOption.Kind.DEFAULT, first.getColumnOptions().get(0).getKind());
roundTrip(table);
first.getColumnOptions().get(0).setDefaultExpression(new LongValue(9));
assertTrue(table.toString().contains("DEFAULT 9 NOT NULL"));
roundTrip(table);
}
}

@ParameterizedTest
@ValueSource(strings = {"DEFAULT", "FOR VALUES IN (1, 2)",
"FOR VALUES FROM (0) TO (10)", "FOR VALUES WITH (MODULUS 4, REMAINDER 0)"})
void sharesOverridesForPartitionChildren(String bound) throws JSQLParserException {
for (String options : new String[] {"", " WITH OPTIONS"}) {
CreateTable table = parse("CREATE TABLE child PARTITION OF public.parent (a" + options
+ " DEFAULT 7 NOT NULL, b, CHECK (a > 0)) " + bound);
assertNotNull(table.getPartitionBound());
assertNull(table.getColumnDefinitions().get(0).getColDataType());
assertNull(table.getColumns());
roundTrip(table);
List<Long> values = new ArrayList<>();
ExpressionDeParser expressions = new ExpressionDeParser() {
@Override
public <S> StringBuilder visit(LongValue value, S context) {
values.add(value.getValue());
return getBuilder().append(value.getValue());
}
};
StringBuilder out = new StringBuilder();
table.accept(new StatementDeParser(expressions, new SelectDeParser(), out));
assertEquals(table.toString(), out.toString());
assertEquals(1, values.stream().filter(v -> v == 7).count());
}
}

@Test
void singleBareOverrideAndOrdinaryTypeParametersRemainDistinct() throws JSQLParserException {
assertNotNull(parse("CREATE TABLE t OF row_type (a)").getColumnDefinitions());
assertNotNull(
parse("CREATE TABLE child PARTITION OF parent (a) DEFAULT").getColumnDefinitions());
assertEquals("numeric (10, 2)", parse("CREATE TABLE t (a numeric(10, 2))")
.getColumnDefinitions().get(0).getColDataType().toString());
assertEquals(List.of("a"), parse("CREATE TABLE t (a) AS SELECT 1").getColumns());
assertEquals(2, CCJSqlParserUtil
.parseStatements("CREATE TABLE t OF row_type (a DEFAULT 1); SELECT 1").size());
}

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(out.toString(), parse(out.toString()).toString());
}
}
Loading