Skip to content

Commit 834d958

Browse files
authored
fix: preserve qualified ALTER TABLE rename targets (#2659)
Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent 78565c8 commit 834d958

4 files changed

Lines changed: 120 additions & 7 deletions

File tree

‎src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.function.Consumer;
2222
import java.util.stream.Collectors;
2323
import net.sf.jsqlparser.expression.Expression;
24+
import net.sf.jsqlparser.schema.Table;
2425
import net.sf.jsqlparser.statement.ReferentialAction;
2526
import net.sf.jsqlparser.statement.ReferentialAction.Action;
2627
import net.sf.jsqlparser.statement.ReferentialAction.Type;
@@ -40,7 +41,7 @@ public enum TableRenameKeyword {
4041
private final Set<ReferentialAction> referentialActions = new LinkedHashSet<>(2);
4142
private AlterOperation operation;
4243
private String optionalSpecifier;
43-
private String newTableName;
44+
private Table newTable;
4445
private TableRenameKeyword tableRenameKeyword = TableRenameKeyword.TO;
4546
private String columnName;
4647
// private ColDataType dataType;
@@ -448,11 +449,25 @@ public void setFkSourceColumns(List<String> fkSourceColumns) {
448449
}
449450

450451
public String getNewTableName() {
451-
return newTableName;
452+
return newTable == null ? null : newTable.getFullyQualifiedName();
452453
}
453454

454455
public void setNewTableName(String newTableName) {
455-
this.newTableName = newTableName;
456+
newTable = newTableName == null ? null : new Table(newTableName, false);
457+
}
458+
459+
/** Returns the structured destination of a table rename. */
460+
public Table getNewTable() {
461+
return newTable;
462+
}
463+
464+
public void setNewTable(Table newTable) {
465+
this.newTable = newTable;
466+
}
467+
468+
public AlterExpression withNewTable(Table newTable) {
469+
setNewTable(newTable);
470+
return this;
456471
}
457472

458473
public TableRenameKeyword getTableRenameKeyword() {
@@ -1013,7 +1028,7 @@ protected void toStringRename(StringBuilder b) {
10131028
}
10141029
b.append(getOldIndex().getName()).append(" TO ").append(getIndex().getName());
10151030
} else {
1016-
b.append("RENAME TO ").append(newTableName);
1031+
b.append("RENAME TO ").append(getNewTableName());
10171032
}
10181033
}
10191034

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import net.sf.jsqlparser.schema.Table;
1616
import net.sf.jsqlparser.statement.LikeClause;
1717
import net.sf.jsqlparser.statement.alter.AlterExpression;
18+
import net.sf.jsqlparser.statement.alter.AlterOperation;
1819
import net.sf.jsqlparser.statement.alter.AlterExpressionPartition;
1920
import net.sf.jsqlparser.statement.alter.AlterExpressionPrimaryKey;
2021
import net.sf.jsqlparser.statement.create.index.CreateIndex;
@@ -47,6 +48,9 @@ public static void visit(CreateIndex createIndex, Consumer<Expression> expressio
4748
/** Visits the structured definitions and expressions belonging to a single ALTER action. */
4849
public static void visit(AlterExpression action, Consumer<Expression> expressions,
4950
Consumer<Table> tables) {
51+
if (action.getOperation() == AlterOperation.RENAME_TABLE) {
52+
accept(action.getNewTable(), tables);
53+
}
5054
if (action.getColumnSetDefaultList() != null) {
5155
action.getColumnSetDefaultList()
5256
.forEach(column -> accept(column.getDefaultExpression(), expressions));

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17296,6 +17296,7 @@ AlterExpression AlterExpressionRenameOp():
1729617296
Token tk;
1729717297
Token tk2;
1729817298
Index index;
17299+
Table newTable;
1729917300
}
1730017301
{
1730117302
<K_RENAME>
@@ -17317,13 +17318,13 @@ AlterExpression AlterExpressionRenameOp():
1731717318
alterExp.setIndex(index);
1731817319
}
1731917320
|
17320-
LOOKAHEAD(2) (
17321+
LOOKAHEAD({ getToken(1).kind == K_TO || getToken(1).kind == K_AS }) (
1732117322
(tk=<K_TO> | tk=<K_AS>) {
1732217323
alterExp.setOperation(AlterOperation.RENAME_TABLE);
1732317324
alterExp.setTableRenameKeyword(AlterExpression.TableRenameKeyword.valueOf(
1732417325
tk.image.toUpperCase(Locale.ROOT)));
1732517326
}
17326-
tk2=KeywordOrIdentifier() { alterExp.setNewTableName(tk2.image); }
17327+
newTable=Table() { alterExp.setNewTable(newTable); }
1732717328
)
1732817329
|
1732917330
LOOKAHEAD(3)
@@ -17340,7 +17341,7 @@ AlterExpression AlterExpressionRenameOp():
1734017341
alterExp.setOperation(AlterOperation.RENAME_TABLE);
1734117342
alterExp.setTableRenameKeyword(AlterExpression.TableRenameKeyword.NONE);
1734217343
}
17343-
tk2=KeywordOrIdentifier() { alterExp.setNewTableName(tk2.image); }
17344+
newTable=Table() { alterExp.setNewTable(newTable); }
1734417345
)
1734517346
)
1734617347
{ return alterExp; }
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2026 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.statement.alter;
11+
12+
import static org.assertj.core.api.Assertions.assertThat;
13+
import static org.junit.jupiter.api.Assertions.assertEquals;
14+
import static org.junit.jupiter.api.Assertions.assertNull;
15+
import static org.junit.jupiter.api.Assertions.assertThrows;
16+
17+
import net.sf.jsqlparser.JSQLParserException;
18+
import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect;
19+
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
20+
import net.sf.jsqlparser.schema.Table;
21+
import net.sf.jsqlparser.util.TablesNamesFinder;
22+
import net.sf.jsqlparser.util.deparser.StatementDeParser;
23+
import org.junit.jupiter.api.Test;
24+
import org.junit.jupiter.params.ParameterizedTest;
25+
import org.junit.jupiter.params.provider.ValueSource;
26+
27+
class MySqlQualifiedRenameTest {
28+
@ParameterizedTest
29+
@ValueSource(strings = {
30+
"ALTER TABLE db1.t RENAME TO db2.t2",
31+
"ALTER TABLE db1.t RENAME AS db2.t2",
32+
"ALTER TABLE db1.t RENAME db2.t2",
33+
"ALTER TABLE `db1`.`t` RENAME TO `db2`.`t2`",
34+
"ALTER TABLE db1.t RENAME TO `db.with.dot`.`table.with.dot`",
35+
"ALTER TABLE db1.t RENAME TO db2.t2, ADD COLUMN other INT",
36+
"ALTER TABLE db1.t RENAME TO t2"
37+
})
38+
void preservesQualifiedTargetsAndRenameKeywords(String sql) throws JSQLParserException {
39+
Alter alter = parse(sql);
40+
assertEquals(sql, alter.toString());
41+
assertRoundTrip(alter);
42+
assertEquals(sql, CCJSqlParserUtil.parse(sql).toString());
43+
}
44+
45+
@Test
46+
void structuredTargetAndLegacyNameStayInSync() throws JSQLParserException {
47+
Alter alter = parse("ALTER TABLE db1.t RENAME TO db2.t2");
48+
AlterExpression rename = alter.getAlterExpressions().get(0);
49+
assertEquals("db2", rename.getNewTable().getSchemaName());
50+
assertEquals("t2", rename.getNewTable().getName());
51+
rename.getNewTable().setName("renamed");
52+
assertEquals("db2.renamed", rename.getNewTableName());
53+
assertThat(new TablesNamesFinder().getTables(alter))
54+
.containsExactlyInAnyOrder("db1.t", "db2.renamed");
55+
assertRoundTrip(alter);
56+
rename.setNewTableName("legacy_name");
57+
assertEquals("legacy_name", rename.getNewTable().getName());
58+
assertNull(rename.getNewTable().getSchemaName());
59+
assertRoundTrip(alter);
60+
rename.withNewTable(new Table("db3", "replacement"));
61+
assertEquals("db3.replacement", rename.getNewTableName());
62+
assertRoundTrip(alter);
63+
rename.setNewTableName(null);
64+
assertNull(rename.getNewTable());
65+
assertNull(rename.getNewTableName());
66+
}
67+
68+
@ParameterizedTest
69+
@ValueSource(strings = {"RENAME COLUMN old_name TO new_name", "RENAME INDEX old_idx TO new_idx",
70+
"RENAME KEY old_idx TO new_idx"})
71+
void doesNotConfuseOtherRenameOperations(String operation) throws JSQLParserException {
72+
Alter alter = parse("ALTER TABLE t " + operation);
73+
assertNull(alter.getAlterExpressions().get(0).getNewTable());
74+
assertRoundTrip(alter);
75+
}
76+
77+
@ParameterizedTest
78+
@ValueSource(strings = {"RENAME TO", "RENAME AS", "RENAME TO db2.", "RENAME TO db2.t2."})
79+
void rejectsIncompleteTargetNames(String operation) {
80+
assertThrows(JSQLParserException.class, () -> parse("ALTER TABLE t " + operation));
81+
}
82+
83+
private static Alter parse(String sql) throws JSQLParserException {
84+
return (Alter) CCJSqlParserUtil.parse(sql, p -> p.withDialect(Dialect.MYSQL));
85+
}
86+
87+
private static void assertRoundTrip(Alter alter) throws JSQLParserException {
88+
StringBuilder buffer = new StringBuilder();
89+
alter.accept(new StatementDeParser(buffer), null);
90+
assertEquals(alter.toString(), buffer.toString());
91+
assertEquals(alter.toString(), parse(buffer.toString()).toString());
92+
}
93+
}

0 commit comments

Comments
 (0)