From 66b077bd933a78aae21b21d54c4be52bd810a551 Mon Sep 17 00:00:00 2001 From: minleejae Date: Fri, 25 Sep 2026 16:32:31 +0900 Subject: [PATCH] fix: replace partition key representations consistently Signed-off-by: minleejae --- .../create/table/TablePartitioning.java | 24 +++-- .../create/PartitionKeyMutationTest.java | 89 +++++++++++++++++++ 2 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 src/test/java/net/sf/jsqlparser/statement/create/PartitionKeyMutationTest.java diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/TablePartitioning.java b/src/main/java/net/sf/jsqlparser/statement/create/table/TablePartitioning.java index 5a287f9b4..44c97ba82 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/TablePartitioning.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/TablePartitioning.java @@ -43,10 +43,10 @@ public List getKeyColumns() { } public void setKeyColumns(List keyColumns) { + if (keyColumns != null) { + clearKeyRepresentation(); + } this.keyColumns = keyColumns; - expression = null; - expressionList = null; - columns = null; } private Type type; @@ -97,8 +97,10 @@ public Expression getExpression() { } public void setExpression(Expression expression) { + if (expression != null) { + clearKeyRepresentation(); + } this.expression = expression; - keyColumns = null; } /** @@ -111,8 +113,10 @@ public ExpressionList getExpressionList() { } public void setExpressionList(ExpressionList expressionList) { + if (expressionList != null) { + clearKeyRepresentation(); + } this.expressionList = expressionList; - keyColumns = null; } public ExpressionList getColumns() { @@ -120,8 +124,18 @@ public ExpressionList getColumns() { } public void setColumns(ExpressionList columns) { + if (columns != null) { + clearKeyRepresentation(); + } this.columns = columns; + } + + /** Selecting a key representation must replace the previously rendered key. */ + private void clearKeyRepresentation() { keyColumns = null; + expression = null; + expressionList = null; + columns = null; } public Integer getAlgorithm() { diff --git a/src/test/java/net/sf/jsqlparser/statement/create/PartitionKeyMutationTest.java b/src/test/java/net/sf/jsqlparser/statement/create/PartitionKeyMutationTest.java new file mode 100644 index 000000000..02dd2ffc3 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/create/PartitionKeyMutationTest.java @@ -0,0 +1,89 @@ +/*- + * #%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.Expression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.create.table.CreateTable; +import net.sf.jsqlparser.statement.create.table.Index; +import net.sf.jsqlparser.statement.create.table.TablePartitioning; +import net.sf.jsqlparser.util.deparser.StatementDeParser; +import org.junit.jupiter.api.Test; + +class PartitionKeyMutationTest { + @Test + void replacingSingleKeyWithSeveralKeysChangesBothRenderers() throws JSQLParserException { + CreateTable table = parse("CREATE TABLE t(id INT,other INT) PARTITION BY RANGE(id)", + Dialect.POSTGRESQL); + table.getPartitioning().setExpressionList( + new ExpressionList(new Column("other"), new Column("id"))); + assertRoundTrip(table, + "CREATE TABLE t (id INT, other INT) PARTITION BY RANGE (other, id)", + Dialect.POSTGRESQL); + assertNull(table.getPartitioning().getExpression()); + } + + @Test + void switchingHashToKeyUsesNewColumnNames() throws JSQLParserException { + CreateTable table = parse("CREATE TABLE t(id INT,other INT) PARTITION BY HASH(id)", + Dialect.MYSQL); + TablePartitioning partition = table.getPartitioning(); + partition.setType(TablePartitioning.Type.KEY); + partition.setColumns(new ExpressionList<>(new Column("other"))); + assertRoundTrip(table, "CREATE TABLE t (id INT, other INT) PARTITION BY KEY (other)", + Dialect.MYSQL); + partition.setType(TablePartitioning.Type.HASH); + partition.setExpression(new Column("id")); + assertNull(partition.getColumns()); + assertRoundTrip(table, "CREATE TABLE t (id INT, other INT) PARTITION BY HASH (id)", + Dialect.MYSQL); + } + + @Test + void attributedKeysReplaceAndAreReplacedByPlainKeys() throws JSQLParserException { + CreateTable table = parse("CREATE TABLE t(id INT,other INT) PARTITION BY RANGE(id,other)", + Dialect.POSTGRESQL); + TablePartitioning partition = table.getPartitioning(); + partition.setKeyColumns( + List.of(new Index.ColumnParams("other").withOperatorClass("int4_ops"))); + assertNull(partition.getExpressionList()); + assertRoundTrip(table, + "CREATE TABLE t (id INT, other INT) PARTITION BY RANGE (other int4_ops)", + Dialect.POSTGRESQL); + partition.setExpression(new Column("id")); + assertNull(partition.getKeyColumns()); + assertRoundTrip(table, "CREATE TABLE t (id INT, other INT) PARTITION BY RANGE (id)", + Dialect.POSTGRESQL); + partition.setColumns(null); + partition.setExpressionList(null); + partition.setKeyColumns(null); + assertRoundTrip(table, "CREATE TABLE t (id INT, other INT) PARTITION BY RANGE (id)", + Dialect.POSTGRESQL); + } + + private static CreateTable parse(String sql, Dialect dialect) throws JSQLParserException { + return (CreateTable) CCJSqlParserUtil.parse(sql, p -> p.withDialect(dialect)); + } + + private static void assertRoundTrip(CreateTable table, String expected, Dialect dialect) + throws JSQLParserException { + assertEquals(expected, table.toString()); + StringBuilder output = new StringBuilder(); + table.accept(new StatementDeParser(output), null); + assertEquals(expected, output.toString()); + assertEquals(expected, parse(output.toString(), dialect).toString()); + } +}