Skip to content

[BUG] JSQLParser 5.4-SNAPSHOT : Hive : INSERT PARTITION bare column inherits the previous item's value #2500

Description

@fudianchn

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:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions