Skip to content

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

@crprashant

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions