Skip to content

Commit ef66801

Browse files
authored
fix: share PostgreSQL typed and partition column overrides (#2693)
Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent dac8159 commit ef66801

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
@@ -15065,6 +15065,7 @@ CreateTable CreateTable(boolean isUsingOrReplace):
1506515065
ColDataType ofType = null;
1506615066
Table parent;
1506715067
List<Table> parents = new ArrayList<Table>();
15068+
ObjectNames typeName;
1506815069
boolean withData;
1506915070
}
1507015071
{
@@ -15085,19 +15086,23 @@ CreateTable CreateTable(boolean isUsingOrReplace):
1508515086
[ LOOKAHEAD(2) tableColumn=TimeTravelAfterAlias() { likeTable.setTimeTravel(tableColumn); } ]
1508615087
{ createTable.setCloneTable(likeTable); likeTable = null; }
1508715088
]
15088-
[ <K_OF> ofType=ColDataType() { createTable.setOfType(ofType); } ]
15089+
[ <K_OF> typeName=RelObjectNames() {
15090+
ofType = new ColDataType();
15091+
ofType.setDataType(typeName.getNames());
15092+
createTable.setOfType(ofType);
15093+
} ]
1508915094
[ LOOKAHEAD(2) <K_PARTITION> <K_OF> partitionOfTable=Table()
1509015095
{ createTable.setPartitionOf(partitionOfTable); } ]
1509115096
[ LOOKAHEAD(2) (
1509215097
LOOKAHEAD("(" ")") "(" ")" { createTable.setTableElements(tableElements); }
1509315098
|
15094-
LOOKAHEAD(3) (
15099+
LOOKAHEAD("(" RelObjectName() ("," RelObjectName())* ")") (
1509515100
"(" tableColumn=RelObjectName() { columns.add(tableColumn); } ("," tableColumn=RelObjectName() { columns.add(tableColumn); } )* ")"
1509615101
)
1509715102
|
1509815103
(
15099-
"(" element=CreateTableElement(ofType != null) { tableElements.add(element); }
15100-
( LOOKAHEAD(2) "," element=CreateTableElement(ofType != null)
15104+
"(" element=CreateTableElement(ofType != null || partitionOfTable != null) { tableElements.add(element); }
15105+
( LOOKAHEAD(2) "," element=CreateTableElement(ofType != null || partitionOfTable != null)
1510115106
{ tableElements.add(element); }
1510215107
)*
1510315108
[ LOOKAHEAD({ Dialect.SQLSERVER.name().equals(getAsString(Feature.dialect))
@@ -15144,8 +15149,16 @@ CreateTable CreateTable(boolean isUsingOrReplace):
1514415149
createTable.setCreateOptionsStrings(createOptions);
1514515150
if (typedTableOptions.size() > 0)
1514615151
createTable.setTableOptions(typedTableOptions);
15147-
if (columns.size() > 0)
15148-
createTable.setColumns(columns);
15152+
if (!columns.isEmpty()) {
15153+
if (ofType != null || partitionOfTable != null) {
15154+
for (String name : columns) {
15155+
tableElements.add(new ColumnDefinition().withColumnName(name));
15156+
}
15157+
createTable.setTableElements(tableElements);
15158+
} else {
15159+
createTable.setColumns(columns);
15160+
}
15161+
}
1514915162
return createTable;
1515015163
}
1515115164
}
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)