Parse UNWIND [...] AS var clause into query */
| 1730 | |
| 1731 | /* Parse UNWIND [...] AS var clause into query */ |
| 1732 | static void parse_unwind_clause(parser_t *p, cbm_query_t *q) { |
| 1733 | advance(p); |
| 1734 | if (check(p, TOK_LBRACKET)) { |
| 1735 | /* Literal list: [1, 2, 3] — collect as JSON array string */ |
| 1736 | advance(p); |
| 1737 | char buf[CBM_SZ_2K] = "["; |
| 1738 | int blen = SKIP_ONE; |
| 1739 | while (!check(p, TOK_RBRACKET) && !check(p, TOK_EOF)) { |
| 1740 | if (blen > SKIP_ONE) { |
| 1741 | buf[blen++] = ','; |
| 1742 | } |
| 1743 | if (check(p, TOK_STRING)) { |
| 1744 | blen += snprintf(buf + blen, sizeof(buf) - blen, "\"%s\"", peek(p)->text); |
| 1745 | advance(p); |
| 1746 | } else if (check(p, TOK_NUMBER)) { |
| 1747 | blen += snprintf(buf + blen, sizeof(buf) - blen, "%s", peek(p)->text); |
| 1748 | advance(p); |
| 1749 | } else { |
| 1750 | advance(p); |
| 1751 | } |
| 1752 | match(p, TOK_COMMA); |
| 1753 | } |
| 1754 | expect(p, TOK_RBRACKET); |
| 1755 | buf[blen++] = ']'; |
| 1756 | buf[blen] = '\0'; |
| 1757 | q->unwind_expr = heap_strdup(buf); |
| 1758 | } else if (check(p, TOK_IDENT)) { |
| 1759 | q->unwind_expr = heap_strdup(advance(p)->text); |
| 1760 | } |
| 1761 | expect(p, TOK_AS); |
| 1762 | const cbm_token_t *alias = expect(p, TOK_IDENT); |
| 1763 | if (alias) { |
| 1764 | q->unwind_alias = heap_strdup(alias->text); |
| 1765 | } |
| 1766 | } |
| 1767 | |
| 1768 | /* Parse a chain of MATCH / OPTIONAL MATCH patterns into query. |
| 1769 | * Returns -1 on error (fills p->error). */ |