Skip to content

ClickHouse: tuple element access followed by a field changes meaning after round-trip #2599

Closed

Description

@s5dsn-eqee

Description

With ClickHouseDialect, a tuple element access followed by a named field prints without spaces around the second dot. The printed SQL parses back as a different query, with no error.

Reproduction

use sqlparser::dialect::ClickHouseDialect;
use sqlparser::parser::Parser;

let sql = "SELECT t.1.name";
let ast = Parser::parse_sql(&ClickHouseDialect {}, sql).unwrap();
let printed = ast[0].to_string();
println!("{printed}"); // SELECT t . 1.name

let reparsed = Parser::parse_sql(&ClickHouseDialect {}, &printed).unwrap();
println!("{}", reparsed[0]); // SELECT t . 1. AS name
Step Result
Input SELECT t.1.name
Parsed CompoundFieldAccess { root: t, access_chain: [Dot(1), Dot(name)] } (correct)
Printed SELECT t . 1.name
Re-parsed SELECT t . 1. AS name: the number 1. with alias name

Expected

The printed output keeps the access chain, e.g. SELECT t . 1 . name, and parses back to the same AST.

Context

ClickHouse's lexer tokenizes t.1.name as t . 1 . name (see the "chained tuple access" disambiguation in src/Parsers/Lexer.cpp), so the initial parse is correct and only Display is wrong.

Follow-up to #2574 (tuple element access). Found with the fuzz_parse_roundtrip fuzz target.

Activity

  1. princejain756 commented on Oct 21, 2026

    @princejain756

    Verified fixed on current main (post-#2675, which added the prev_is_number handling in CompoundFieldAccess display).

    let sql = "SELECT t.1.name";
    let ast = Parser::parse_sql(&ClickHouseDialect {}, sql).unwrap();
    let printed = ast[0].to_string(); // SELECT t . 1 . name
    let reparsed = Parser::parse_sql(&ClickHouseDialect {}, &printed).unwrap();
    assert_eq!(ast, reparsed); // passes

    t.1.name, t.1.name.2, t.1.2.x, and (t.1).name all round-trip with identical ASTs now. This can be closed.

  2. s5dsn-eqee commented on Oct 22, 2026

    @s5dsn-eqee
    ContributorAuthor

    Thank you @princejain756

  3. princejain756 commented on Oct 22, 2026

    @princejain756

    Happy to help. #2675 covers the reparsing side; the report can probably close.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions