Skip to content

Fix parsing ALTER TABLE ... ADD COLUMNS (...) #2087

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class AlterExpression implements Serializable {
private String commentText;

private boolean hasColumn = false;
private boolean hasColumns = false;


private boolean useBrackets = false;
Expand All @@ -80,6 +81,10 @@ public boolean hasColumn() {
return hasColumn;
}

public boolean hasColumns() {
return hasColumns;
}

public boolean useBrackets() {
return useBrackets;
}
Expand All @@ -92,6 +97,10 @@ public void hasColumn(boolean hasColumn) {
this.hasColumn = hasColumn;
}

public void hasColumns(boolean hasColumns) {
this.hasColumns = hasColumns;
}

public String getFkSourceSchema() {
return fkSourceSchema;
}
Expand Down Expand Up @@ -503,6 +512,8 @@ public String toString() {
} else {
if (hasColumn) {
b.append("COLUMN ");
} else if (hasColumns) {
b.append("COLUMNS ");
}
if (useIfNotExists
&& operation == AlterOperation.ADD) {
Expand Down
68 changes: 37 additions & 31 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,7 @@ DescribeStatement Describe(): {
DescribeStatement stmt = new DescribeStatement();
Token tk = null;
} {
(tk=<K_DESCRIBE> | tk=<K_DESC>)
(tk=<K_DESCRIBE> | tk=<K_DESC>)
table = Table() { stmt.setDescribeType(tk.image).setTable(table); }
{
return stmt;
Expand Down Expand Up @@ -1388,13 +1388,13 @@ Statement RefreshMaterializedView(): {
}
{
<K_REFRESH> <K_MATERIALIZED> <K_VIEW>
[ LOOKAHEAD(2) <K_CONCURRENTLY> { concurrently = true; } ]
[ LOOKAHEAD(2) <K_CONCURRENTLY> { concurrently = true; } ]
view = Table()
[
<K_WITH> { refreshMode = RefreshMode.WITH_DATA; }
[
[
<K_NO> { refreshMode = RefreshMode.WITH_NO_DATA; }
]
]
<K_DATA>
]
captureRest = captureRest()
Expand Down Expand Up @@ -2017,7 +2017,7 @@ The following tokens are allowed as Names for Schema, Table, Column and Aliases
String RelObjectNameWithoutValue() :
{ Token tk = null; }
{
( tk=<DATA_TYPE> | tk=<S_IDENTIFIER> | tk=<S_QUOTED_IDENTIFIER> | tk=<K_DATE_LITERAL> | tk=<K_DATETIMELITERAL> | tk=<K_STRING_FUNCTION_NAME> | tk=<K_ISOLATION> | tk=<K_TIME_KEY_EXPR> | tk=<K_TEXT_LITERAL>
( tk=<DATA_TYPE> | tk=<S_IDENTIFIER> | tk=<S_QUOTED_IDENTIFIER> | tk=<K_DATE_LITERAL> | tk=<K_DATETIMELITERAL> | tk=<K_STRING_FUNCTION_NAME> | tk=<K_ISOLATION> | tk=<K_TIME_KEY_EXPR> | tk=<K_TEXT_LITERAL>
| tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="ALGORITHM" | tk="ALTER" | tk="ANALYZE" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="BASE64" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOCK" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="COSTS" | tk="COUNT" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="END" | tk="ERROR" | tk="ESCAPE" | tk="EXCLUDE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXTENDED" | tk="EXTRACT" | tk="FALSE" | tk="FILTER" | tk="FIRST" | tk="FLUSH" | tk="FN" | tk="FOLLOWING" | tk="FORMAT" | tk="FULLTEXT" | tk="FUNCTION" | tk="GRANT" | tk="GROUP_CONCAT" | tk="GUARD" | tk="HASH" | tk="HIGH_PRIORITY" | tk="HISTORY" | tk="HOPPING" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCREMENT" | tk="INDEX" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="ISNULL" | tk="JSON" | tk="JSON_ARRAY" | tk="JSON_ARRAYAGG" | tk="JSON_OBJECT" | tk="JSON_OBJECTAGG" | tk="KEEP" | tk="KEY" | tk="KEYS" | tk="LAST" | tk="LEADING" | tk="LINK" | tk="LOCAL" | tk="LOCKED" | tk="LOG" | tk="LONGTEXT" | tk="LOOP" | tk="LOW_PRIORITY" | tk="MATCH" | tk="MATCHED" | tk="MATERIALIZED" | tk="MAX" | tk="MAXVALUE" | tk="MEDIUMTEXT" | tk="MEMBER" | tk="MERGE" | tk="MIN" | tk="MINVALUE" | tk="MODIFY" | tk="MOVEMENT" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="PARALLEL" | tk="PARENT" | tk="PARTITION" | tk="PATH" | tk="PERCENT" | tk="PLACING" | tk="PLAN" | tk="PRECEDING" | tk="PRIMARY" | tk="PURGE" | tk="QUERY" | tk="QUICK" | tk="QUIESCE" | tk="RANGE" | tk="RAW" | tk="READ" | tk="RECURSIVE" | tk="RECYCLEBIN" | tk="REFERENCES" | tk="REFRESH" | tk="REGEXP" | tk="REGEXP_LIKE" | tk="REGISTER" | tk="REMOTE" | tk="RENAME" | tk="REPEATABLE" | tk="REPLACE" | tk="RESET" | tk="RESPECT" | tk="RESTART" | tk="RESTRICT" | tk="RESTRICTED" | tk="RESUMABLE" | tk="RESUME" | tk="RETURN" | tk="RLIKE" | tk="ROLLBACK" | tk="ROLLUP" | tk="ROOT" | tk="ROW" | tk="ROWS" | tk="RR" | tk="RS" | tk="SAFE_CAST" | tk="SAVEPOINT" | tk="SCHEMA" | tk="SECURE" | tk="SEED" | tk="SEPARATOR" | tk="SEQUENCE" | tk="SESSION" | tk="SETS" | tk="SHARE" | tk="SHOW" | tk="SHUTDOWN" | tk="SIBLINGS" | tk="SIGNED" | tk="SIMILAR" | tk="SIZE" | tk="SKIP" | tk="STORED" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYNONYM" | tk="SYSTEM" | tk="TABLE" | tk="TABLESPACE" | tk="TEMP" | tk="TEMPORARY" | tk="TEXT" | tk="THEN" | tk="TIMEOUT" | tk="TIMESTAMPTZ" | tk="TIMEZONE" | tk="TINYTEXT" | tk="TO" | tk="TRIGGER" | tk="TRUE" | tk="TRUNCATE" | tk="TRY_CAST" | tk="TUMBLING" | tk="TYPE" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VERBOSE" | tk="VIEW" | tk="VOLATILE" | tk="WAIT" | tk="WITHIN" | tk="WITHOUT" | tk="WITHOUT_ARRAY_WRAPPER" | tk="WORK" | tk="XML" | tk="XMLAGG" | tk="XMLDATA" | tk="XMLSCHEMA" | tk="XMLTEXT" | tk="XSINIL" | tk="YAML" | tk="YES" | tk="ZONE" )
{ return tk.image; }
}
Expand Down Expand Up @@ -2227,7 +2227,7 @@ TableStatement TableStatement():
List<OrderByElement> orderByElements = null;
Limit limit = null;
Offset offset = null;
TableStatement tableStatement = new TableStatement();
TableStatement tableStatement = new TableStatement();
}{
<K_TABLE>
table = Table()
Expand Down Expand Up @@ -2560,12 +2560,12 @@ PlainSelect PlainSelect() #PlainSelect:
[ LOOKAHEAD(<K_LIMIT>, { limit==null }) limit = LimitWithOffset() { plainSelect.setLimit(limit); } ]
[ LOOKAHEAD(<K_FETCH>) fetch = Fetch() { plainSelect.setFetch(fetch); } ]
[ LOOKAHEAD(<K_WITH> <K_ISOLATION>) withIsolation = WithIsolation() { plainSelect.setIsolation(withIsolation); } ]
[ LOOKAHEAD(2)
<K_FOR>
[ LOOKAHEAD(2)
<K_FOR>
(
<K_UPDATE> { plainSelect.setForMode(ForMode.UPDATE); }
| <K_SHARE> { plainSelect.setForMode(ForMode.SHARE); }
| (<K_NO> <K_KEY> <K_UPDATE> { plainSelect.setForMode(ForMode.NO_KEY_UPDATE); })
<K_UPDATE> { plainSelect.setForMode(ForMode.UPDATE); }
| <K_SHARE> { plainSelect.setForMode(ForMode.SHARE); }
| (<K_NO> <K_KEY> <K_UPDATE> { plainSelect.setForMode(ForMode.NO_KEY_UPDATE); })
| (<K_KEY> <K_SHARE> { plainSelect.setForMode(ForMode.KEY_SHARE); })
)
[ LOOKAHEAD(2) <K_OF> updateTable = Table() { plainSelect.setForUpdateTable(updateTable); } ]
Expand Down Expand Up @@ -3480,7 +3480,7 @@ GroupByElement GroupByColumnReferences():
<K_GROUP> <K_BY>
(
LOOKAHEAD(2) (
<K_GROUPING> <K_SETS>
<K_GROUPING> <K_SETS>
"("
list = GroupingSet() { groupBy.addGroupingSet(list); }
( LOOKAHEAD(2) "," list = GroupingSet() { groupBy.addGroupingSet(list); })*
Expand All @@ -3490,7 +3490,7 @@ GroupByElement GroupByColumnReferences():
(
list = ExpressionList() { groupBy.setGroupByExpressions(list); }
(
LOOKAHEAD(2) <K_GROUPING> <K_SETS>
LOOKAHEAD(2) <K_GROUPING> <K_SETS>
"("
list = GroupingSet() { groupBy.addGroupingSet(list); }
( LOOKAHEAD(2) "," list = GroupingSet() { groupBy.addGroupingSet(list); })*
Expand Down Expand Up @@ -6064,10 +6064,10 @@ CreateIndex CreateIndex():
)
|
(
[ <K_USING> using=<S_IDENTIFIER> {
[ <K_USING> using=<S_IDENTIFIER> {
index.setUsing(using.image);
createIndex.setIndexTypeBeforeOn(true);
}
}
]
<K_ON> table=Table()
)
Expand Down Expand Up @@ -6605,8 +6605,8 @@ List<String> CreateViewTailComment():
if (op != null) {
result.add(op);
}
result.add(tk2.image);
}
result.add(tk2.image);
}
{ return result;}
}

Expand Down Expand Up @@ -7071,11 +7071,17 @@ AlterExpression AlterExpression():
)
|
LOOKAHEAD(3) (
( LOOKAHEAD(2) <K_COLUMN> { alterExp.hasColumn(true); } )?
( LOOKAHEAD(2)
(
<K_COLUMN> { alterExp.hasColumn(true); }
|
<K_COLUMNS> { alterExp.hasColumns(true); }
)
)?
[ <K_IF> <K_NOT> <K_EXISTS> { alterExp.setUseIfNotExists(true); } ]
(
LOOKAHEAD(4) (
"("
"("
{ alterExp.useBrackets(true);}
alterExpressionColumnDataType = AlterExpressionColumnDataType() {
alterExp.addColDataType(alterExpressionColumnDataType);
Expand All @@ -7089,22 +7095,22 @@ AlterExpression AlterExpression():
")"
)
|
LOOKAHEAD(2) alterExpressionColumnDataType = AlterExpressionColumnDataType()
LOOKAHEAD(2) alterExpressionColumnDataType = AlterExpressionColumnDataType()
{ alterExp.addColDataType(alterExpressionColumnDataType); }
|
LOOKAHEAD(3) alterExpressionColumnDropNotNull = AlterExpressionColumnDropNotNull()
LOOKAHEAD(3) alterExpressionColumnDropNotNull = AlterExpressionColumnDropNotNull()
{ alterExp.addColDropNotNull( alterExpressionColumnDropNotNull);}
|
alterExpressionColumnDropDefault = AlterExpressionColumnDropDefault()
alterExpressionColumnDropDefault = AlterExpressionColumnDropDefault()
{ alterExp.addColDropDefault( alterExpressionColumnDropDefault); }
)
)
|
(
"(" alterExpressionColumnDataType = AlterExpressionColumnDataType() { alterExp.addColDataType(alterExpressionColumnDataType); }
(","
alterExpressionColumnDataType = AlterExpressionColumnDataType() { alterExp.addColDataType(alterExpressionColumnDataType); }
)*
(","
alterExpressionColumnDataType = AlterExpressionColumnDataType() { alterExp.addColDataType(alterExpressionColumnDataType); }
)*
")"
)
|
Expand Down Expand Up @@ -7156,7 +7162,7 @@ AlterExpression AlterExpression():
[LOOKAHEAD(2) (<K_ON> (tk=<K_DELETE> | tk=<K_UPDATE>) action = Action()
{ fkIndex.setReferentialAction(ReferentialAction.Type.from(tk.image), action); }
)]
[LOOKAHEAD(2) (<K_ON> (tk=<K_DELETE> | tk=<K_UPDATE>) action = Action()
[LOOKAHEAD(2) (<K_ON> (tk=<K_DELETE> | tk=<K_UPDATE>) action = Action()
{ fkIndex.setReferentialAction(ReferentialAction.Type.from(tk.image), action); }
)]
constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); }
Expand Down Expand Up @@ -7310,18 +7316,18 @@ AlterExpression AlterExpression():
)
|
LOOKAHEAD(2)
(<K_RENAME> ((<K_INDEX> {alterExp.setOperation(AlterOperation.RENAME_INDEX);}
| <K_KEY> {alterExp.setOperation(AlterOperation.RENAME_KEY);})
(<K_RENAME> ((<K_INDEX> {alterExp.setOperation(AlterOperation.RENAME_INDEX);}
| <K_KEY> {alterExp.setOperation(AlterOperation.RENAME_KEY);})
| <K_CONSTRAINT> { alterExp.setOperation(AlterOperation.RENAME_CONSTRAINT); }
)
)
(tk=<S_IDENTIFIER> | tk=<S_QUOTED_IDENTIFIER>){
alterExp.setOldIndex(new Index().withName(tk.image));
}
}
<K_TO>
(tk2=<S_IDENTIFIER> | tk2=<S_QUOTED_IDENTIFIER>){
index = new Index().withName(tk2.image);
alterExp.setIndex(index);
}
}
)
|
LOOKAHEAD(2) <K_TRUNCATE> <K_PARTITION> { alterExp.setOperation(AlterOperation.TRUNCATE_PARTITION); } truncatePartitionName = RelObjectName() { alterExp.setTruncatePartitionName(truncatePartitionName); }
Expand Down
17 changes: 17 additions & 0 deletions src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,23 @@ public void testAlterTableAddColumn() throws JSQLParserException {
assertEquals("varchar (255)", colDataTypes.get(0).getColDataType().toString());
}

@Test
public void testAlterTableAddColumnsWhitespace() throws JSQLParserException {
Statement stmt =
CCJSqlParserUtil.parse(
"ALTER TABLE test_catalog.test20241014.tt ADD COLUMNS (apples string, bees int)");
assertTrue(stmt instanceof Alter);
Alter alter = (Alter) stmt;
assertEquals("test_catalog.test20241014.tt", alter.getTable().getFullyQualifiedName());
AlterExpression alterExp = alter.getAlterExpressions().get(0);
assertNotNull(alterExp);
List<ColumnDataType> colDataTypes = alterExp.getColDataTypeList();
assertEquals("apples", colDataTypes.get(0).getColumnName());
assertEquals("string", colDataTypes.get(0).getColDataType().toString());
assertEquals("bees", colDataTypes.get(1).getColumnName());
assertEquals("int", colDataTypes.get(1).getColDataType().toString());
}

@Test
public void testAlterTableAddColumn_ColumnKeyWordImplicit() throws JSQLParserException {
Statement stmt = CCJSqlParserUtil.parse("ALTER TABLE mytable ADD mycolumn varchar (255)");
Expand Down
Loading