with_props=false skips the per-label/per-type JSON property-key discovery: * those json_each() scans walk EVERY row of each label/type (minutes-scale on * multi-million-node graphs) and get_architecture only needs the counts. */
| 6398 | * those json_each() scans walk EVERY row of each label/type (minutes-scale on |
| 6399 | * multi-million-node graphs) and get_architecture only needs the counts. */ |
| 6400 | static int get_schema_impl(cbm_store_t *s, const char *project, cbm_schema_info_t *out, |
| 6401 | bool with_props) { |
| 6402 | memset(out, 0, sizeof(*out)); |
| 6403 | if (!s || !s->db) { |
| 6404 | return CBM_NOT_FOUND; |
| 6405 | } |
| 6406 | |
| 6407 | /* Node labels */ |
| 6408 | { |
| 6409 | const char *sql = "SELECT label, COUNT(*) FROM nodes WHERE project = ?1 GROUP BY label " |
| 6410 | "ORDER BY COUNT(*) DESC;"; |
| 6411 | sqlite3_stmt *stmt = NULL; |
| 6412 | if (sqlite3_prepare_v2(s->db, sql, CBM_NOT_FOUND, &stmt, NULL) != SQLITE_OK || !stmt) { |
| 6413 | if (stmt) { |
| 6414 | sqlite3_finalize(stmt); |
| 6415 | } |
| 6416 | return CBM_NOT_FOUND; |
| 6417 | } |
| 6418 | bind_text(stmt, SKIP_ONE, project); |
| 6419 | |
| 6420 | int cap = ST_INIT_CAP_8; |
| 6421 | int n = 0; |
| 6422 | cbm_label_count_t *arr = malloc(cap * sizeof(cbm_label_count_t)); |
| 6423 | if (!arr) { |
| 6424 | sqlite3_finalize(stmt); |
| 6425 | return CBM_NOT_FOUND; |
| 6426 | } |
| 6427 | int scan_rc16; |
| 6428 | while ((scan_rc16 = sqlite3_step(stmt)) == SQLITE_ROW) { |
| 6429 | if (n >= cap) { |
| 6430 | int new_cap = cap * ST_GROWTH; |
| 6431 | void *tmp = realloc(arr, new_cap * sizeof(cbm_label_count_t)); |
| 6432 | if (!tmp) { |
| 6433 | for (int i = 0; i < n; i++) { |
| 6434 | safe_str_free(&arr[i].label); |
| 6435 | } |
| 6436 | free(arr); |
| 6437 | sqlite3_finalize(stmt); |
| 6438 | return CBM_NOT_FOUND; |
| 6439 | } |
| 6440 | arr = tmp; |
| 6441 | cap = new_cap; |
| 6442 | } |
| 6443 | arr[n].label = heap_strdup((const char *)sqlite3_column_text(stmt, 0)); |
| 6444 | arr[n].count = sqlite3_column_int(stmt, SKIP_ONE); |
| 6445 | arr[n].properties = NULL; |
| 6446 | arr[n].property_count = 0; |
| 6447 | n++; |
| 6448 | } |
| 6449 | if (scan_rc16 != SQLITE_DONE) { /* SCANCHK:16:stmt */ |
| 6450 | store_set_error_sqlite(s, "row scan aborted"); |
| 6451 | sqlite3_finalize(stmt); |
| 6452 | out->node_labels = arr; |
| 6453 | out->node_label_count = n; |
| 6454 | return CBM_STORE_ERR; |
| 6455 | } |
| 6456 | sqlite3_finalize(stmt); |
| 6457 | out->node_labels = arr; |
no test coverage detected