Skip to content

Commit 5798b83

Browse files
committed
fix: share PostgreSQL typed and partition column overrides
Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent 0f58f7f commit 5798b83

2 files changed

Lines changed: 118 additions & 6 deletions

File tree

‎src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt‎

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14968,6 +14968,7 @@ CreateTable CreateTable(boolean isUsingOrReplace):
1496814968
Table partitionOfTable = null;
1496914969
PartitionBound partitionBound = null;
1497014970
ColDataType ofType = null;
14971+
ObjectNames typeName;
1497114972
}
1497214973
{
1497314974
{ createTable.setOrReplace(isUsingOrReplace);}
@@ -14987,17 +14988,21 @@ CreateTable CreateTable(boolean isUsingOrReplace):
1498714988
[ LOOKAHEAD(2) tableColumn=TimeTravelAfterAlias() { likeTable.setTimeTravel(tableColumn); } ]
1498814989
{ createTable.setCloneTable(likeTable); likeTable = null; }
1498914990
]
14990-
[ <K_OF> ofType=ColDataType() { createTable.setOfType(ofType); } ]
14991+
[ <K_OF> typeName=RelObjectNames() {
14992+
ofType = new ColDataType();
14993+
ofType.setDataType(typeName.getNames());
14994+
createTable.setOfType(ofType);
14995+
} ]
1499114996
[ LOOKAHEAD(2) <K_PARTITION> <K_OF> partitionOfTable=Table()
1499214997
{ createTable.setPartitionOf(partitionOfTable); } ]
1499314998
[ LOOKAHEAD(2) (
14994-
LOOKAHEAD(3) (
14999+
LOOKAHEAD("(" RelObjectName() ("," RelObjectName())* ")") (
1499515000
"(" tableColumn=RelObjectName() { columns.add(tableColumn); } ("," tableColumn=RelObjectName() { columns.add(tableColumn); } )* ")"
1499615001
)
1499715002
|
1499815003
(
14999-
"(" element=CreateTableElement(ofType != null) { tableElements.add(element); }
15000-
( LOOKAHEAD(2) "," element=CreateTableElement(ofType != null)
15004+
"(" element=CreateTableElement(ofType != null || partitionOfTable != null) { tableElements.add(element); }
15005+
( LOOKAHEAD(2) "," element=CreateTableElement(ofType != null || partitionOfTable != null)
1500115006
{ tableElements.add(element); }
1500215007
)*
1500315008
[ LOOKAHEAD({ Dialect.SQLSERVER.name().equals(getAsString(Feature.dialect))
@@ -15035,8 +15040,16 @@ CreateTable CreateTable(boolean isUsingOrReplace):
1503515040
createTable.setCreateOptionsStrings(createOptions);
1503615041
if (typedTableOptions.size() > 0)
1503715042
createTable.setTableOptions(typedTableOptions);
15038-
if (columns.size() > 0)
15039-
createTable.setColumns(columns);
15043+
if (!columns.isEmpty()) {
15044+
if (ofType != null || partitionOfTable != null) {
15045+
for (String name : columns) {
15046+
tableElements.add(new ColumnDefinition().withColumnName(name));
15047+
}
15048+
createTable.setTableElements(tableElements);
15049+
} else {
15050+
createTable.setColumns(columns);
15051+
}
15052+
}
1504015053
return createTable;
1504115054
}
1504215055
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2019 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.statement.create;
11+
12+
import static org.junit.jupiter.api.Assertions.*;
13+
import java.util.ArrayList;
14+
import java.util.List;
15+
import net.sf.jsqlparser.JSQLParserException;
16+
import net.sf.jsqlparser.expression.LongValue;
17+
import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect;
18+
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
19+
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
20+
import net.sf.jsqlparser.statement.create.table.ColumnOption;
21+
import net.sf.jsqlparser.statement.create.table.CreateTable;
22+
import net.sf.jsqlparser.util.deparser.ExpressionDeParser;
23+
import net.sf.jsqlparser.util.deparser.SelectDeParser;
24+
import net.sf.jsqlparser.util.deparser.StatementDeParser;
25+
import org.junit.jupiter.api.Test;
26+
import org.junit.jupiter.params.ParameterizedTest;
27+
import org.junit.jupiter.params.provider.ValueSource;
28+
29+
class PostgreSqlTableColumnOverridesTest {
30+
@ParameterizedTest
31+
@ValueSource(strings = {"row_type", "public.row_type", "\"Type.Schema\".\"Row.Type\""})
32+
void keepsTypeNameSeparateFromFirstColumn(String type) throws JSQLParserException {
33+
for (String withOptions : new String[] {"", " WITH OPTIONS"}) {
34+
CreateTable table = parse("CREATE TABLE t OF " + type + " (a" + withOptions
35+
+ " DEFAULT 7 NOT NULL, b, CHECK (a > 0))");
36+
assertEquals(type, table.getOfType().getDataType());
37+
assertNull(table.getOfType().getArgumentsStringList());
38+
assertEquals(2, table.getColumnDefinitions().size());
39+
ColumnDefinition first = table.getColumnDefinitions().get(0);
40+
assertNull(first.getColDataType());
41+
assertEquals(!withOptions.isEmpty(), first.isWithOptions());
42+
assertEquals("b", table.getColumnDefinitions().get(1).getColumnName());
43+
assertEquals(ColumnOption.Kind.DEFAULT, first.getColumnOptions().get(0).getKind());
44+
roundTrip(table);
45+
first.getColumnOptions().get(0).setDefaultExpression(new LongValue(9));
46+
assertTrue(table.toString().contains("DEFAULT 9 NOT NULL"));
47+
roundTrip(table);
48+
}
49+
}
50+
51+
@ParameterizedTest
52+
@ValueSource(strings = {"DEFAULT", "FOR VALUES IN (1, 2)",
53+
"FOR VALUES FROM (0) TO (10)", "FOR VALUES WITH (MODULUS 4, REMAINDER 0)"})
54+
void sharesOverridesForPartitionChildren(String bound) throws JSQLParserException {
55+
for (String options : new String[] {"", " WITH OPTIONS"}) {
56+
CreateTable table = parse("CREATE TABLE child PARTITION OF public.parent (a" + options
57+
+ " DEFAULT 7 NOT NULL, b, CHECK (a > 0)) " + bound);
58+
assertNotNull(table.getPartitionBound());
59+
assertNull(table.getColumnDefinitions().get(0).getColDataType());
60+
assertNull(table.getColumns());
61+
roundTrip(table);
62+
List<Long> values = new ArrayList<>();
63+
ExpressionDeParser expressions = new ExpressionDeParser() {
64+
@Override
65+
public <S> StringBuilder visit(LongValue value, S context) {
66+
values.add(value.getValue());
67+
return getBuilder().append(value.getValue());
68+
}
69+
};
70+
StringBuilder out = new StringBuilder();
71+
table.accept(new StatementDeParser(expressions, new SelectDeParser(), out));
72+
assertEquals(table.toString(), out.toString());
73+
assertEquals(1, values.stream().filter(v -> v == 7).count());
74+
}
75+
}
76+
77+
@Test
78+
void singleBareOverrideAndOrdinaryTypeParametersRemainDistinct() throws JSQLParserException {
79+
assertNotNull(parse("CREATE TABLE t OF row_type (a)").getColumnDefinitions());
80+
assertNotNull(
81+
parse("CREATE TABLE child PARTITION OF parent (a) DEFAULT").getColumnDefinitions());
82+
assertEquals("numeric (10, 2)", parse("CREATE TABLE t (a numeric(10, 2))")
83+
.getColumnDefinitions().get(0).getColDataType().toString());
84+
assertEquals(List.of("a"), parse("CREATE TABLE t (a) AS SELECT 1").getColumns());
85+
assertEquals(2, CCJSqlParserUtil
86+
.parseStatements("CREATE TABLE t OF row_type (a DEFAULT 1); SELECT 1").size());
87+
}
88+
89+
private static CreateTable parse(String sql) throws JSQLParserException {
90+
return (CreateTable) CCJSqlParserUtil.parse(sql, p -> p.withDialect(Dialect.POSTGRESQL));
91+
}
92+
93+
private static void roundTrip(CreateTable table) throws JSQLParserException {
94+
StringBuilder out = new StringBuilder();
95+
table.accept(new StatementDeParser(out));
96+
assertEquals(table.toString(), out.toString());
97+
assertEquals(out.toString(), parse(out.toString()).toString());
98+
}
99+
}

0 commit comments

Comments
 (0)