Skip to content

Keywords are parsed as functions in select statements #1909

Open
@crepererum

Description

@crepererum

Abstract

Qualified names like of the form <table>.<column> are sometimes parsed as functions, like in:

SELECT t.user FROM t;

Current Behavior

This is done with cargo run --example cli -- test.sql --generic:

select t.user from t;

results in:

[
    Query(
        Query {
            with: None,
            body: Select(
                Select {
                    select_token: TokenWithSpan {
                        token: Word(
                            Word {
                                value: "select",
                                quote_style: None,
                                keyword: SELECT,
                            },
                        ),
                        span: Span(Location(1,1)..Location(1,7)),
                    },
                    distinct: None,
                    top: None,
                    top_before_distinct: false,
                    projection: [
                        UnnamedExpr(
                            Function(
                                Function {
                                    name: ObjectName(
                                        [
                                            Identifier(
                                                Ident {
                                                    value: "t",
                                                    quote_style: None,
                                                    span: Span(Location(1,8)..Location(1,9)),
                                                },
                                            ),
                                            Identifier(
                                                Ident {
                                                    value: "user",
                                                    quote_style: None,
                                                    span: Span(Location(1,10)..Location(1,14)),
                                                },
                                            ),
                                        ],
                                    ),
                                    uses_odbc_syntax: false,
                                    parameters: None,
                                    args: None,
                                    filter: None,
                                    null_treatment: None,
                                    over: None,
                                    within_group: [],
                                },
                            ),
                        ),
                    ],
                    into: None,
                    from: [
                        TableWithJoins {
                            relation: Table {
                                name: ObjectName(
                                    [
                                        Identifier(
                                            Ident {
                                                value: "t",
                                                quote_style: None,
                                                span: Span(Location(1,20)..Location(1,21)),
                                            },
                                        ),
                                    ],
                                ),
                                alias: None,
                                args: None,
                                with_hints: [],
                                version: None,
                                with_ordinality: false,
                                partitions: [],
                                json_path: None,
                                sample: None,
                                index_hints: [],
                            },
                            joins: [],
                        },
                    ],
                    lateral_views: [],
                    prewhere: None,
                    selection: None,
                    group_by: Expressions(
                        [],
                        [],
                    ),
                    cluster_by: [],
                    distribute_by: [],
                    sort_by: [],
                    having: None,
                    named_window: [],
                    qualify: None,
                    window_before_qualify: false,
                    value_table_mode: None,
                    connect_by: None,
                    flavor: Standard,
                },
            ),
            order_by: None,
            limit_clause: None,
            fetch: None,
            locks: [],
            for_clause: None,
            settings: None,
            format_clause: None,
            pipe_operators: [],
        },
    ),
]

and cargo run --example cli -- test.sql --postgres is the same:

[
    Query(
        Query {
            with: None,
            body: Select(
                Select {
                    select_token: TokenWithSpan {
                        token: Word(
                            Word {
                                value: "select",
                                quote_style: None,
                                keyword: SELECT,
                            },
                        ),
                        span: Span(Location(1,1)..Location(1,7)),
                    },
                    distinct: None,
                    top: None,
                    top_before_distinct: false,
                    projection: [
                        UnnamedExpr(
                            Function(
                                Function {
                                    name: ObjectName(
                                        [
                                            Identifier(
                                                Ident {
                                                    value: "t",
                                                    quote_style: None,
                                                    span: Span(Location(1,8)..Location(1,9)),
                                                },
                                            ),
                                            Identifier(
                                                Ident {
                                                    value: "user",
                                                    quote_style: None,
                                                    span: Span(Location(1,10)..Location(1,14)),
                                                },
                                            ),
                                        ],
                                    ),
                                    uses_odbc_syntax: false,
                                    parameters: None,
                                    args: None,
                                    filter: None,
                                    null_treatment: None,
                                    over: None,
                                    within_group: [],
                                },
                            ),
                        ),
                    ],
                    into: None,
                    from: [
                        TableWithJoins {
                            relation: Table {
                                name: ObjectName(
                                    [
                                        Identifier(
                                            Ident {
                                                value: "t",
                                                quote_style: None,
                                                span: Span(Location(1,20)..Location(1,21)),
                                            },
                                        ),
                                    ],
                                ),
                                alias: None,
                                args: None,
                                with_hints: [],
                                version: None,
                                with_ordinality: false,
                                partitions: [],
                                json_path: None,
                                sample: None,
                                index_hints: [],
                            },
                            joins: [],
                        },
                    ],
                    lateral_views: [],
                    prewhere: None,
                    selection: None,
                    group_by: Expressions(
                        [],
                        [],
                    ),
                    cluster_by: [],
                    distribute_by: [],
                    sort_by: [],
                    having: None,
                    named_window: [],
                    qualify: None,
                    window_before_qualify: false,
                    value_table_mode: None,
                    connect_by: None,
                    flavor: Standard,
                },
            ),
            order_by: None,
            limit_clause: None,
            fetch: None,
            locks: [],
            for_clause: None,
            settings: None,
            format_clause: None,
            pipe_operators: [],
        },
    ),
]

Expected Behavior

I think this should parse similar to

select t.foo from t;

with cargo run --example cli -- test.sql --generic:

[
    Query(
        Query {
            with: None,
            body: Select(
                Select {
                    select_token: TokenWithSpan {
                        token: Word(
                            Word {
                                value: "select",
                                quote_style: None,
                                keyword: SELECT,
                            },
                        ),
                        span: Span(Location(1,1)..Location(1,7)),
                    },
                    distinct: None,
                    top: None,
                    top_before_distinct: false,
                    projection: [
                        UnnamedExpr(
                            CompoundIdentifier(
                                [
                                    Ident {
                                        value: "t",
                                        quote_style: None,
                                        span: Span(Location(1,8)..Location(1,9)),
                                    },
                                    Ident {
                                        value: "foo",
                                        quote_style: None,
                                        span: Span(Location(1,10)..Location(1,13)),
                                    },
                                ],
                            ),
                        ),
                    ],
                    into: None,
                    from: [
                        TableWithJoins {
                            relation: Table {
                                name: ObjectName(
                                    [
                                        Identifier(
                                            Ident {
                                                value: "t",
                                                quote_style: None,
                                                span: Span(Location(1,19)..Location(1,20)),
                                            },
                                        ),
                                    ],
                                ),
                                alias: None,
                                args: None,
                                with_hints: [],
                                version: None,
                                with_ordinality: false,
                                partitions: [],
                                json_path: None,
                                sample: None,
                                index_hints: [],
                            },
                            joins: [],
                        },
                    ],
                    lateral_views: [],
                    prewhere: None,
                    selection: None,
                    group_by: Expressions(
                        [],
                        [],
                    ),
                    cluster_by: [],
                    distribute_by: [],
                    sort_by: [],
                    having: None,
                    named_window: [],
                    qualify: None,
                    window_before_qualify: false,
                    value_table_mode: None,
                    connect_by: None,
                    flavor: Standard,
                },
            ),
            order_by: None,
            limit_clause: None,
            fetch: None,
            locks: [],
            for_clause: None,
            settings: None,
            format_clause: None,
            pipe_operators: [],
        },
    ),
]

Others

Also see PostgreSQL:

psql (17.5 (Debian 17.5-1.pgdg120+1))
Type "help" for help.

postgres=# create table t(a int, "user" text);
CREATE TABLE
postgres=# insert into t values (1, 'foo');
INSERT 0 1
postgres=# select t.user from t;
 user
------
 foo
(1 row)

Interestingly, even the plain user works:

postgres=# select user from t;
   user
----------
 postgres
(1 row)

References

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