split() treats the delimiter as a regular expression while replace() treats it literally
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 82/100
Research direction
Read src/backend/utils/adt/agtype.c, starting at age_split(), and compare its delimiter handling with age_replace(). Run the supplied psql reproduction through both the Cypher and direct SQL paths. Done means literal delimiters such as '.', '|', and '+' split correctly without regex escaping, while replacement behavior remains consistent.
Written by the indexing model from the issue text.
Description
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)
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.
- Dominant language
- C
- Stars
- 4.9k
- Forks
- 529
- Avg merge
- 8d 15h
- Merged PRs (30d)
- 3
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from apache/age
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
apache/age#2576 · 1 reaction ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
apache/age#2520 · 3 comments ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
apache/age#2514 · 4 comments ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 30/100
Maintainers usually reply within 1 day
Similar issues
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
Missing zeroOpen
Difficulty 1/5 Under an hour Newbie friendliness 95/100
projecthorus/radiosonde_auto_rx#1116 · 1 comment ·