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