Cypher keyword-named aliases cannot be referenced back as variables
- Dominant language
- C
- Stars
- 4.8k
- Forks
- 523
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 9
Description
# 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 `. 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)
```sql
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:
```sql
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:
```sql
SELECT * FROM cypher('g',
$$ WITH 1 AS `count` RETURN `count` $$
) AS (a agtype);
```
## Related
- #2355 — original report (alias binding, fixed in #2415).
- #2415 — alias-binding fix; this issue tracks the remaining
read-back asymmetry.
Contributor guide
Assessment
This issue has not been assessed yet.