Skip to content

Cypher keyword-named aliases cannot be referenced back as variables #2416

Description

@crprashant

Followup: keyword-named aliases cannot be referenced back

After #2415 lands, safe_keywords (e.g. count, exists, coalesce,
match, where, order, limit, distinct, ...) are accepted as
aliases in RETURN/WITH/YIELD/UNWIND ... AS <name>. However,
once such an alias is bound, it still cannot be referenced as a
variable later in the same query.

Reproducer (against the branch from #2415)

SELECT * FROM cypher('g', $$ WITH 1 AS count RETURN count $$) AS (a agtype);
-- ERROR:  syntax error at end of input

SELECT * FROM cypher('g', $$ UNWIND [1,2,3] AS count RETURN count $$) AS (a agtype);
-- ERROR:  syntax error at end of input

SELECT * FROM cypher('g', $$ WITH 5 AS limit RETURN limit + 1 AS x $$) AS (a agtype);
-- ERROR:  syntax error at or near "+"

The alias binds successfully (so projecting any literal under
AS count works), but the parser cannot reduce a bare COUNT token to
an expr_var, so the second mention of count fails.

Root cause

expr_var: var_name reads the variable through var_name, which still
accepts only symbolic_name (i.e. IDENTIFIER). #2415 deliberately
broadens only the alias-binding path (var_name_alias) because
broadening var_name itself reintroduces ~156 shift/reduce conflicts
in bison (keyword tokens collide with their syntactic roles inside
expressions and patterns).

A complete fix likely requires either:

  1. A scoped grammar refactor that resolves the conflicts (probably with
    precedence directives or a hand-written lookahead helper), or
  2. Lexer-level handling that re-tags an already-bound alias name as
    IDENTIFIER for the rest of the query (rejected by Apache AGE
    before — context-sensitive lexing), or
  3. A semantic-analysis pass that rewrites expr_var references to
    safe_keywords before parsing reaches the conflict (intrusive).

Workaround today

Use a plain identifier when the alias needs to be referenced:

SELECT * FROM cypher('g',
    $$ WITH 1 AS cnt RETURN cnt $$
) AS (a agtype);

or backtick-quote the alias if the keyword form is desired downstream:

SELECT * FROM cypher('g',
    $$ WITH 1 AS `count` RETURN `count` $$
) AS (a agtype);

Related

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