Opaque store generation for pagination cursors: "u g ", * or "legacy" when the DB predates store_meta (read-only opens never create * it). A cursor whose embedded generation mismatches the store's current one * is stale — the graph may have changed under it. */
| 1644 | * it). A cursor whose embedded generation mismatches the store's current one |
| 1645 | * is stale — the graph may have changed under it. */ |
| 1646 | int cbm_store_generation(cbm_store_t *s, char *buf, size_t bufsz) { |
| 1647 | if (!s || !s->db || !buf || bufsz == 0) { |
| 1648 | return CBM_STORE_ERR; |
| 1649 | } |
| 1650 | snprintf(buf, bufsz, "legacy"); |
| 1651 | sqlite3_stmt *stmt = NULL; |
| 1652 | if (sqlite3_prepare_v2(s->db, |
| 1653 | "SELECT (SELECT v FROM store_meta WHERE k='db_uid')," |
| 1654 | " (SELECT v FROM store_meta WHERE k='mutation_gen');", |
| 1655 | CBM_NOT_FOUND, &stmt, NULL) != SQLITE_OK) { |
| 1656 | return CBM_STORE_OK; /* pre-migration DB: stable "legacy" generation */ |
| 1657 | } |
| 1658 | if (sqlite3_step(stmt) == SQLITE_ROW) { |
| 1659 | const char *uid = (const char *)sqlite3_column_text(stmt, 0); |
| 1660 | const char *gen = (const char *)sqlite3_column_text(stmt, SKIP_ONE); |
| 1661 | if (uid && gen) { |
| 1662 | snprintf(buf, bufsz, "u%sg%s", uid, gen); |
| 1663 | } |
| 1664 | } |
| 1665 | sqlite3_finalize(stmt); |
| 1666 | return CBM_STORE_OK; |
| 1667 | } |
| 1668 | |
| 1669 | int cbm_store_get_project(cbm_store_t *s, const char *name, cbm_project_t *out) { |
| 1670 | sqlite3_stmt *stmt = |
no outgoing calls
no test coverage detected