AI disclosure: this issue was prepared with AI coding agents, reviewed and revised line by line by me.
Failing SQL Feature:
In INSERT ... PARTITION, a bare (dynamic) partition column that follows an item with a value inherits that item's value instead of keeping null. The deparsed statement silently turns the dynamic column into a constant assignment, changing the statement's semantics.
Verified combinations (master 1e4e92b and the 5.3 release jar):
| PARTITION spec |
parsed items |
(dtime = '20220403', region) |
dtime = '20220403', region = '20220403' (wrong) |
(a, b = '1', c) |
a = null, b = '1', c = '1' (wrong) |
(dtime, hour = '10') |
dtime = null, hour = '10' (correct) |
(dtime = '20220403', hour = '10') |
both correct |
(dtime) |
dtime = null (correct) |
The trigger is: an item without a value following an item with one. Affects both INSERT OVERWRITE TABLE ... PARTITION and INSERT INTO TABLE ... PARTITION (shared Insert() grammar).
Root cause in Partitions() (src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt, around line 3924, introduced with #2323):
List<Partition> Partitions():
{
List<Partition> partitions = new ArrayList<Partition>();
Column tableColumn;
Expression valueExpression = null;
}
{
(
tableColumn=Column() [ "=" valueExpression=Expression() ]
{ partitions.add( new Partition (tableColumn, valueExpression)); }
)
( LOOKAHEAD(2) (
","
tableColumn=Column() [ "=" valueExpression=Expression() ]
{ partitions.add( new Partition (tableColumn, valueExpression)); }
) )*
...
valueExpression is declared once for the whole production and reused for every item. When the optional "=" Expression() is skipped for a bare column, valueExpression still holds the value of an earlier item, which then lands in new Partition(tableColumn, valueExpression).
Suggested fix: reset valueExpression = null at the start of each item. Partition already renders a bare column when the value is null, so no deparser change should be needed.
SQL Example:
Insert insert = (Insert) CCJSqlParserUtil.parse(
"INSERT OVERWRITE TABLE t PARTITION (dtime = '20220403', region) SELECT code, region FROM src");
for (Partition p : insert.getPartitions()) {
System.out.println(p.getColumn() + " -> " + p.getValue());
}
Output on master:
dtime -> '20220403'
region -> '20220403'
Expected:
dtime -> '20220403'
region -> null
The deparsed statement is INSERT OVERWRITE TABLE t PARTITION (dtime = '20220403', region = '20220403') SELECT code, region FROM src, so region no longer takes its value dynamically from the SELECT list.
Software Information:
AI disclosure: this issue was prepared with AI coding agents, reviewed and revised line by line by me.
Failing SQL Feature:
In
INSERT ... PARTITION, a bare (dynamic) partition column that follows an item with a value inherits that item's value instead of keepingnull. The deparsed statement silently turns the dynamic column into a constant assignment, changing the statement's semantics.Verified combinations (master
1e4e92band the 5.3 release jar):(dtime = '20220403', region)dtime = '20220403',region = '20220403'(wrong)(a, b = '1', c)a = null,b = '1',c = '1'(wrong)(dtime, hour = '10')dtime = null,hour = '10'(correct)(dtime = '20220403', hour = '10')(dtime)dtime = null(correct)The trigger is: an item without a value following an item with one. Affects both
INSERT OVERWRITE TABLE ... PARTITIONandINSERT INTO TABLE ... PARTITION(sharedInsert()grammar).Root cause in
Partitions()(src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt, around line 3924, introduced with #2323):valueExpressionis declared once for the whole production and reused for every item. When the optional"=" Expression()is skipped for a bare column,valueExpressionstill holds the value of an earlier item, which then lands innew Partition(tableColumn, valueExpression).Suggested fix: reset
valueExpression = nullat the start of each item.Partitionalready renders a bare column when the value isnull, so no deparser change should be needed.SQL Example:
Output on master:
Expected:
The deparsed statement is
INSERT OVERWRITE TABLE t PARTITION (dtime = '20220403', region = '20220403') SELECT code, region FROM src, soregionno longer takes its value dynamically from the SELECT list.Software Information:
1e4e92b, also verified on the 5.3 release jar (Partitions()exists since [feat/refactor] AllColumns and AllTableColumns-Support for JSON_OBJECT #2323; 5.0 does not parse these forms at all)