Skip to content

Commit 75bbcaf

Browse files
committed
fix: preserve unbounded partition markers during expression rewrites
1 parent 182d320 commit 75bbcaf

3 files changed

Lines changed: 87 additions & 19 deletions

File tree

src/main/java/net/sf/jsqlparser/statement/create/table/PartitionBound.java

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.io.Serializable;
1313
import java.util.function.Consumer;
1414
import net.sf.jsqlparser.expression.Expression;
15+
import net.sf.jsqlparser.schema.Column;
1516
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
1617

1718
/** A PostgreSQL declarative-partition bound. */
@@ -123,9 +124,9 @@ public void appendTo(StringBuilder sql, Consumer<Expression> expressionPrinter)
123124
switch (type) {
124125
case RANGE:
125126
sql.append("FOR VALUES FROM (");
126-
expressionPrinter.accept(fromExpressions);
127+
appendRangeValues(sql, fromExpressions, expressionPrinter);
127128
sql.append(") TO (");
128-
expressionPrinter.accept(toExpressions);
129+
appendRangeValues(sql, toExpressions, expressionPrinter);
129130
sql.append(')');
130131
break;
131132
case LIST:
@@ -147,4 +148,68 @@ public void appendTo(StringBuilder sql, Consumer<Expression> expressionPrinter)
147148
break;
148149
}
149150
}
151+
152+
/** Visits active bound expressions, excluding the MINVALUE/MAXVALUE range markers. */
153+
public void visitExpressions(Consumer<Expression> expressions) {
154+
if (type == null) {
155+
return;
156+
}
157+
switch (type) {
158+
case RANGE:
159+
visitRangeValues(fromExpressions, expressions);
160+
visitRangeValues(toExpressions, expressions);
161+
break;
162+
case LIST:
163+
if (inExpressions != null) {
164+
expressions.accept(inExpressions);
165+
}
166+
break;
167+
case HASH:
168+
if (modulus != null) {
169+
expressions.accept(modulus);
170+
}
171+
if (remainder != null) {
172+
expressions.accept(remainder);
173+
}
174+
break;
175+
default:
176+
break;
177+
}
178+
}
179+
180+
private static void visitRangeValues(ExpressionList<Expression> values,
181+
Consumer<Expression> expressions) {
182+
if (values != null) {
183+
values.stream().filter(value -> !isRangeMarker(value)).forEach(expressions);
184+
}
185+
}
186+
187+
private static void appendRangeValues(StringBuilder sql, ExpressionList<Expression> values,
188+
Consumer<Expression> expressions) {
189+
if (values == null) {
190+
sql.append("null");
191+
return;
192+
}
193+
for (int i = 0; i < values.size(); i++) {
194+
if (i > 0) {
195+
sql.append(", ");
196+
}
197+
Expression value = values.get(i);
198+
if (isRangeMarker(value)) {
199+
sql.append(value);
200+
} else {
201+
expressions.accept(value);
202+
}
203+
}
204+
}
205+
206+
private static boolean isRangeMarker(Expression expression) {
207+
if (!(expression instanceof Column)) {
208+
return false;
209+
}
210+
Column column = (Column) expression;
211+
return column.getTable() == null && ("MINVALUE".equalsIgnoreCase(column.getColumnName())
212+
|| "MAXVALUE".equalsIgnoreCase(column.getColumnName()));
213+
}
214+
150215
}

src/main/java/net/sf/jsqlparser/util/TableDefinitionTraversal.java

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -116,23 +116,8 @@ public static void visit(TablePartitioning partitioning, Consumer<Expression> ex
116116

117117
/** Visits expressions belonging to the selected PostgreSQL bound type. */
118118
public static void visit(PartitionBound bound, Consumer<Expression> expressions) {
119-
if (bound == null || bound.getType() == null) {
120-
return;
121-
}
122-
switch (bound.getType()) {
123-
case RANGE:
124-
accept(bound.getFromExpressions(), expressions);
125-
accept(bound.getToExpressions(), expressions);
126-
break;
127-
case LIST:
128-
accept(bound.getInExpressions(), expressions);
129-
break;
130-
case HASH:
131-
accept(bound.getModulus(), expressions);
132-
accept(bound.getRemainder(), expressions);
133-
break;
134-
default:
135-
break;
119+
if (bound != null) {
120+
bound.visitExpressions(expressions);
136121
}
137122
}
138123

src/test/java/net/sf/jsqlparser/statement/create/PartitionTraversalTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,29 @@ public <S> Void visit(LongValue value, S context) {
7171
assertThat(visited).containsExactly("id", "id", "1", "0", "10");
7272
}
7373

74+
@Test
75+
void rangeMarkersAreNotVisitedAsColumnReferences() throws JSQLParserException {
76+
List<String> columns = new ArrayList<>();
77+
ExpressionVisitorAdapter<Void> expressions = new ExpressionVisitorAdapter<Void>() {
78+
@Override
79+
public <S> Void visit(Column column, S context) {
80+
columns.add(column.getColumnName());
81+
return null;
82+
}
83+
};
84+
CCJSqlParserUtil.parse("ALTER TABLE parent ATTACH PARTITION child "
85+
+ "FOR VALUES FROM (MINVALUE) TO (MAXVALUE)")
86+
.accept(new StatementVisitorAdapter<>(new SelectVisitorAdapter<>(expressions)),
87+
null);
88+
assertThat(columns).isEmpty();
89+
}
90+
7491
@ParameterizedTest
7592
@ValueSource(strings = {
7693
"CREATE TABLE t (id INT) PARTITION BY HASH (id + 1) PARTITIONS 2",
7794
"ALTER TABLE t PARTITION BY RANGE COLUMNS (id)",
7895
"CREATE TABLE child PARTITION OF parent FOR VALUES FROM (0) TO (10)",
96+
"CREATE TABLE child PARTITION OF parent FOR VALUES FROM (MINVALUE) TO (MAXVALUE)",
7997
"ALTER TABLE parent ATTACH PARTITION child FOR VALUES IN (1, 2)",
8098
"ALTER TABLE parent ATTACH PARTITION child FOR VALUES WITH (MODULUS 4, REMAINDER 1)",
8199
"ALTER TABLE parent ATTACH PARTITION child DEFAULT"

0 commit comments

Comments
 (0)