| 2899 | } |
| 2900 | |
| 2901 | int cbm_store_coverage_replace_ex(cbm_store_t *s, const char *project, |
| 2902 | const cbm_coverage_row_t *rows, int count, |
| 2903 | const cbm_coverage_meta_t *meta) { |
| 2904 | if (!s || !s->db || !project || count < 0 || (count > 0 && !rows)) { |
| 2905 | return CBM_STORE_ERR; |
| 2906 | } |
| 2907 | if (exec_sql(s, "BEGIN;") != CBM_STORE_OK) { |
| 2908 | return CBM_STORE_ERR; |
| 2909 | } |
| 2910 | /* Sub-block timings (publish.timing style): coverage_replace measured 9 s |
| 2911 | * on the TypeScript corpus and the caller-level block could not say WHY — |
| 2912 | * delete, 13k row inserts with large error_ranges payloads, the NOT-IN |
| 2913 | * prune, meta, and COMMIT are very different suspects. */ |
| 2914 | struct timespec cov_t0; |
| 2915 | struct timespec cov_t1; |
| 2916 | long cov_ms[5] = {0, 0, 0, 0, 0}; |
| 2917 | long long cov_detail_bytes = 0; |
| 2918 | cbm_clock_gettime(CLOCK_MONOTONIC, &cov_t0); |
| 2919 | sqlite3_stmt *del = NULL; |
| 2920 | if (sqlite3_prepare_v2(s->db, "DELETE FROM index_coverage WHERE project = ?1;", CBM_NOT_FOUND, |
| 2921 | &del, NULL) != SQLITE_OK) { |
| 2922 | store_set_error_sqlite(s, "coverage delete prepare"); |
| 2923 | (void)exec_sql(s, "ROLLBACK;"); |
| 2924 | return CBM_STORE_ERR; |
| 2925 | } |
| 2926 | bind_text(del, SKIP_ONE, project); |
| 2927 | int rc = sqlite3_step(del); |
| 2928 | sqlite3_finalize(del); |
| 2929 | if (rc != SQLITE_DONE) { |
| 2930 | store_set_error_sqlite(s, "coverage delete"); |
| 2931 | (void)exec_sql(s, "ROLLBACK;"); |
| 2932 | return CBM_STORE_ERR; |
| 2933 | } |
| 2934 | cbm_clock_gettime(CLOCK_MONOTONIC, &cov_t1); |
| 2935 | cov_ms[0] = |
| 2936 | (cov_t1.tv_sec - cov_t0.tv_sec) * 1000 + (cov_t1.tv_nsec - cov_t0.tv_nsec) / 1000000; |
| 2937 | cov_t0 = cov_t1; |
| 2938 | sqlite3_stmt *ins = NULL; |
| 2939 | if (sqlite3_prepare_v2( |
| 2940 | s->db, |
| 2941 | "INSERT OR REPLACE INTO index_coverage (project, rel_path, kind, detail) " |
| 2942 | "VALUES (?1, ?2, ?3, ?4);", |
| 2943 | CBM_NOT_FOUND, &ins, NULL) != SQLITE_OK) { |
| 2944 | store_set_error_sqlite(s, "coverage insert prepare"); |
| 2945 | (void)exec_sql(s, "ROLLBACK;"); |
| 2946 | return CBM_STORE_ERR; |
| 2947 | } |
| 2948 | for (int i = 0; i < count; i++) { |
| 2949 | if (!rows[i].rel_path || !rows[i].kind) { |
| 2950 | continue; |
| 2951 | } |
| 2952 | bind_text(ins, SKIP_ONE, project); |
| 2953 | bind_text(ins, ST_COL_2, rows[i].rel_path); |
| 2954 | bind_text(ins, ST_COL_3, rows[i].kind); |
| 2955 | cov_detail_bytes += rows[i].detail ? (long long)strlen(rows[i].detail) : 0; |
| 2956 | bind_text(ins, CBM_SZ_4, rows[i].detail ? rows[i].detail : ""); |
| 2957 | if (sqlite3_step(ins) != SQLITE_DONE) { |
| 2958 | store_set_error_sqlite(s, "coverage insert"); |