From 5706bf52f010e69a92c4b05e962fd7dd0a2f0348 Mon Sep 17 00:00:00 2001 From: Martin Vogel Date: Wed, 10 Jun 2026 18:25:08 +0200 Subject: [PATCH] Extract url_path for the dump index via real JSON parsing The dump path sliced url_path out of the properties string with strstr/strchr, returning ESCAPED bytes and cutting at embedded escaped quotes, while the index's backing column is GENERATED AS json_extract(properties,'$.url_path') and yields the unescaped value. The mismatch left edges 'missing from index idx_edges_url_path' under PRAGMA integrity_check once the formerly-malformed route props became valid JSON. url_path is now parsed with yyjson so the indexed value matches json_extract exactly. --- src/graph_buffer/graph_buffer.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/graph_buffer/graph_buffer.c b/src/graph_buffer/graph_buffer.c index 1f90f0a35..ef94f9839 100644 --- a/src/graph_buffer/graph_buffer.c +++ b/src/graph_buffer/graph_buffer.c @@ -23,6 +23,7 @@ enum { GB_DEDUP_LOOKAHEAD = 1, /* compare current with next element */ }; #include "graph_buffer/graph_buffer.h" +#include // url_path extraction must match json_extract semantics #include "store/store.h" #include "sqlite_writer.h" #include "foundation/hash_table.h" @@ -1170,21 +1171,28 @@ int cbm_gbuf_merge(cbm_gbuf_t *dst, cbm_gbuf_t *src) { /* ── Dump / Flush ────────────────────────────────────────────────── */ /* Extract url_path value from a properties JSON string. - * Returns heap-allocated string or NULL. Caller must free. */ + * Returns heap-allocated string or NULL. Caller must free. + * Parses real JSON: the dump writer feeds this value into idx_edges_url_path, + * whose backing column is GENERATED AS json_extract(properties,'$.url_path'). + * Naive byte slicing returned the ESCAPED text (and cut at embedded \\") + * while json_extract yields the unescaped value — the mismatch left rows + * "missing from index idx_edges_url_path" under PRAGMA integrity_check. */ static char *extract_url_path(const char *props) { - if (!props) { + if (!props || !strstr(props, "\"url_path\"")) { return NULL; } - const char *key = strstr(props, "\"url_path\":\""); - if (!key) { + yyjson_doc *doc = yyjson_read(props, strlen(props), 0); + if (!doc) { return NULL; } - key += GB_URL_PATH_PREFIX; /* strlen("\"url_path\":\"") */ - const char *end = strchr(key, '"'); - if (!end || end <= key) { - return NULL; + char *out = NULL; + yyjson_val *v = yyjson_obj_get(yyjson_doc_get_root(doc), "url_path"); + if (v && yyjson_is_str(v)) { + const char *sv = yyjson_get_str(v); + out = cbm_strndup(sv, strlen(sv)); } - return cbm_strndup(key, (size_t)(end - key)); + yyjson_doc_free(doc); + return out; } /* Remap a temp edge ID to its final sequential ID, or 0 if out of range. */