hkjiang26 opened a new issue, #2568:
URL: https://github.com/apache/age/issues/2568
**AGE Version:** extension 1.8.0 on PostgreSQL 18.6
**Installation Method:** Docker
**API:** Cypher and direct SQL
## Steps to reproduce (paste into psql as-is)
```sql
LOAD 'age';
SET search_path = ag_catalog, public;
-- Cypher path (re-run: DROP GRAPH xdb CASCADE first)
SELECT * FROM create_graph('xdb');
SELECT * FROM cypher('xdb', $$ RETURN split('a.b.c', '.') $$) AS (r agtype);
-- SQL path (same C function, no graph needed)
SELECT age_split('a.b.c', '.'); -- -> ["", "", "", "", "", ""]
SELECT age_split('a1b1c', '1'); -- -> ["a", "b", "c"] (plain
delimiter: works)
SELECT age_replace('a.b.c', '.', '-'); -- -> "a-b-c"
SELECT age_split('a.b.c', '\.'); -- -> ["a", "b", "c"] (only because
it is regex-escaped)
SELECT age_split('a|b', '|'); -- -> ["a", "|", "b"]
SELECT age_split('a+b+c', '+'); -- -> ERROR: invalid regular
expression: quantifier operand invalid
```
## Expected behavior
openCypher defines the split delimiter as a **literal string**:
`split('a.b.c', '.')` → `['a','b','c']`. Neo4j, Memgraph and FalkorDB all
return this without any escaping, and `replace('a.b.c', '.', '-')` → `'a-b-c'`
in AGE too — so both functions must interpret '.' identically.
## Actual behavior
- `split('a.b.c', '.')` → `["","","","","",""]` (six empty strings): the
delimiter is compiled as a **regular expression**, so '.' matches every
character.
- `split('a1b1c', '1')` → `["a","b","c"]`: plain delimiters work, so the
regex interpretation only surfaces for metacharacters — exactly where queries
silently break.
- `split('a.b.c', '\.')` → `["a","b","c"]`: correct **only** because the
user manually regex-escapes the dot.
- `split('a|b', '|')` → `["a","|","b"]`: the empty-alternation regex splits
at every position.
- `split('a+b+c', '+')` → `ERROR: invalid regular expression: quantifier
operand invalid`.
- `replace('a.b.c', '.', '-')` → `"a-b-c"`: the same engine treats the same
delimiter literally.
The engine is internally inconsistent, deviates from openCypher and all
sibling engines, and silently corrupts results for common literal delimiters
('.', '|', '+', ...).
## Root cause
`age_split()` (src/backend/utils/adt/agtype.c) passes the delimiter verbatim
to PostgreSQL's `regexp_split_to_array()`, which compiles it as a regular
expression; `age_replace()` performs a literal replacement. Cypher
`split()`/`replace()` are rewritten to these same SQL functions, so both APIs
are affected.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]