Skip to content

Commit b127d10

Browse files
committed
fix: support comment column names in ALTER TABLE
Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent 60c8dc2 commit b127d10

3 files changed

Lines changed: 113 additions & 1 deletion

File tree

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3066,6 +3066,7 @@ Token KeywordOrIdentifier():
30663066
| tk = <K_DATA>
30673067
| tk = <K_TYPE>
30683068
| tk = <K_VERSION>
3069+
| tk = <K_COMMENT>
30693070
)
30703071
{ return tk; }
30713072
}
@@ -17262,7 +17263,8 @@ AlterExpression AlterExpressionAddAlterModify():
1726217263
constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); }
1726317264
[ AlterExpressionUsingIndex(alterExp) ]
1726417265
|
17265-
LOOKAHEAD(2) (
17266+
// Include the literal: COLUMN comment is a column definition, not a COMMENT clause.
17267+
LOOKAHEAD(RelObjectName() <K_COMMENT> <S_CHAR_LITERAL>) (
1726617268
sk3=RelObjectName() <K_COMMENT> tk=<S_CHAR_LITERAL> { alterExp.withColumnName(sk3).withCommentText(tk.image); }
1726717269
)
1726817270
|

src/site/sphinx/usage.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,25 @@ One grammar covers every supported RDBMS, but a few pieces of syntax mean differ
811811

812812
Features set explicitly *after* the preset win over it.
813813

814+
ALTER column names
815+
~~~~~~~~~~~~~~~~~~
816+
817+
Non-reserved names such as ``comment`` work unquoted in ``ADD``, ``MODIFY``,
818+
``CHANGE``, ``DROP`` and ``RENAME`` column actions. The ``COLUMN`` keyword does
819+
not change how the name is interpreted. Column definitions remain editable:
820+
821+
.. code-block:: java
822+
823+
Alter alter = (Alter) CCJSqlParserUtil.parse(
824+
"ALTER TABLE t MODIFY COLUMN comment TEXT",
825+
parser -> parser.withDialect(Dialect.MYSQL));
826+
AlterExpression.ColumnDataType column = alter.getAlterExpressions().get(0)
827+
.getColDataTypeList().get(0);
828+
column.setColumnName("notes");
829+
column.getColDataType().setDataType("LONGTEXT");
830+
// ALTER TABLE t MODIFY COLUMN notes LONGTEXT
831+
String sql = alter.toString();
832+
814833
PostgreSQL names and literals
815834
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
816835

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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.junit.jupiter.api.Assertions.*;
13+
import net.sf.jsqlparser.JSQLParserException;
14+
import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect;
15+
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
16+
import net.sf.jsqlparser.util.deparser.StatementDeParser;
17+
import org.junit.jupiter.api.Test;
18+
import org.junit.jupiter.params.ParameterizedTest;
19+
import org.junit.jupiter.params.provider.ValueSource;
20+
21+
class AlterCommentColumnTest {
22+
@ParameterizedTest
23+
@ValueSource(strings = {
24+
"ADD COLUMN comment TEXT", "ADD comment TEXT", "MODIFY COLUMN comment TEXT",
25+
"MODIFY comment TEXT", "MODIFY COLUMN `comment` TEXT",
26+
"MODIFY COLUMN comment TEXT COMMENT 'note' AFTER id",
27+
"CHANGE COLUMN comment comment2 TEXT", "CHANGE COLUMN old_name comment TEXT",
28+
"DROP COLUMN comment", "DROP comment", "RENAME COLUMN comment TO comment2",
29+
"RENAME COLUMN old_name TO comment"
30+
})
31+
void roundTripsUnquotedCommentColumn(String action) throws JSQLParserException {
32+
for (Dialect dialect : new Dialect[] {null, Dialect.MYSQL}) {
33+
Alter alter = parse("ALTER TABLE t " + action, dialect);
34+
assertEquals(1, alter.getAlterExpressions().size());
35+
assertRoundTrip(alter, dialect);
36+
}
37+
}
38+
39+
@Test
40+
void exposesEditableColumnDefinitionInsteadOfColumnComment() throws JSQLParserException {
41+
Alter alter = parse("ALTER TABLE t MODIFY COLUMN comment TEXT", Dialect.MYSQL);
42+
AlterExpression action = alter.getAlterExpressions().get(0);
43+
assertEquals(AlterOperation.MODIFY, action.getOperation());
44+
assertNull(action.getCommentText());
45+
AlterExpression.ColumnDataType column = action.getColDataTypeList().get(0);
46+
assertEquals("comment", column.getColumnName());
47+
assertEquals("TEXT", column.getColDataType().getDataType());
48+
column.setColumnName("notes");
49+
column.getColDataType().setDataType("LONGTEXT");
50+
assertEquals("ALTER TABLE t MODIFY COLUMN notes LONGTEXT", alter.toString());
51+
assertRoundTrip(alter, Dialect.MYSQL);
52+
}
53+
54+
@Test
55+
void exposesBothNamesInRenameAndChange() throws JSQLParserException {
56+
Alter rename = parse("ALTER TABLE t RENAME COLUMN comment TO notes", Dialect.MYSQL);
57+
AlterExpression action = rename.getAlterExpressions().get(0);
58+
assertEquals("comment", action.getColumnOldName());
59+
assertEquals("notes", action.getColumnName());
60+
action.setColumnName("remarks");
61+
assertEquals("ALTER TABLE t RENAME COLUMN comment TO remarks", rename.toString());
62+
assertRoundTrip(rename, Dialect.MYSQL);
63+
Alter change = parse("ALTER TABLE t CHANGE COLUMN comment notes TEXT", Dialect.MYSQL);
64+
assertEquals("comment", change.getAlterExpressions().get(0).getColumnOldName());
65+
assertEquals("notes",
66+
change.getAlterExpressions().get(0).getColDataTypeList().get(0).getColumnName());
67+
}
68+
69+
@ParameterizedTest
70+
@ValueSource(strings = {"ALTER c COMMENT 'description'", "COMMENT = 'table description'",
71+
"DROP COLUMN type", "DROP INDEX idx", "DROP CONSTRAINT ck", "RENAME TO other",
72+
"RENAME INDEX idx TO other_idx", "RENAME CONSTRAINT ck TO other_ck"})
73+
void preservesOtherAlterBranches(String action) throws JSQLParserException {
74+
assertRoundTrip(parse("ALTER TABLE t " + action, null), null);
75+
}
76+
77+
private static Alter parse(String sql, Dialect dialect) throws JSQLParserException {
78+
return (Alter) CCJSqlParserUtil.parse(sql, p -> {
79+
if (dialect != null) {
80+
p.withDialect(dialect);
81+
}
82+
});
83+
}
84+
85+
private static void assertRoundTrip(Alter alter, Dialect dialect) throws JSQLParserException {
86+
StringBuilder buffer = new StringBuilder();
87+
alter.accept(new StatementDeParser(buffer), null);
88+
assertEquals(alter.toString(), buffer.toString());
89+
assertEquals(alter.toString(), parse(buffer.toString(), dialect).toString());
90+
}
91+
}

0 commit comments

Comments
 (0)