sources/cg_stats.c (100 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #if defined(CQL_AMALGAM_LEAN) && !defined(CQL_AMALGAM_STATS) // stubs to avoid link errors cql_noexport void cg_stats_main(struct ast_node *root) {} #else #include <stdint.h> #include "cql.h" #include "ast.h" #include "cg_stats.h" #include "cg_common.h" #include "charbuf.h" #include "symtab.h" static CSTR cg_stats_current_proc; static symtab *stats_data; static charbuf *stats_output; static symtab *stats_stoplist; static void cg_stats_accumulate(ast_node *node) { CSTR type = node->type; if (!symtab_find(stats_stoplist, type)) { symtab_entry *entry = symtab_find(stats_data, type); if (!entry) { symtab_add(stats_data, type, (void *)(intptr_t)1); } else { // swizzle an int out of the generic storage intptr_t val = (intptr_t)entry->val; val++; entry->val = (void *)val; } } // Check the left and right nodes. if (ast_has_left(node)) { cg_stats_accumulate(node->left); } if (ast_has_right(node)) { cg_stats_accumulate(node->right); } } static void cg_stats_create_proc_stmt(ast_node *ast) { Contract(is_ast_create_proc_stmt(ast)); EXTRACT_STRING(name, ast->left); cg_stats_current_proc = name; stats_data = symtab_new(); cg_stats_accumulate(ast); uint32_t count = stats_data->count; symtab_entry *stats = symtab_copy_sorted_payload(stats_data, default_symtab_comparator); for (uint32_t i = 0; i < count; i++) { symtab_entry *entry = &stats[i]; bprintf(stats_output, "\"%s\",\"%s\",%lld\n", name, entry->sym, (llint_t)entry->val); } free(stats); symtab_delete(stats_data); stats_data = NULL; } static void cg_stats_stmt_list(ast_node *head) { for (ast_node *ast = head; ast; ast = ast->right) { EXTRACT_STMT_AND_MISC_ATTRS(stmt, misc_attrs, ast); if (is_ast_create_proc_stmt(stmt)) { cg_stats_create_proc_stmt(stmt); } } } static void cg_stoplist() { stats_stoplist = symtab_new(); symtab *s = stats_stoplist; // These are optional containers that are always present // their child is the interesting node, e.g. "opt_having" might be present // "select_having" is always present symtab_add(s, "select_having", NULL); symtab_add(s, "select_where", NULL); symtab_add(s, "select_offset", NULL); symtab_add(s, "select_groupby", NULL); symtab_add(s, "select_orderby", NULL); symtab_add(s, "select_limit", NULL); symtab_add(s, "select_from_etc", NULL); symtab_add(s, "table_or_subquery_list", NULL); symtab_add(s, "groupby_list", NULL); symtab_add(s, "name_list", NULL); symtab_add(s, "arg_list", NULL); symtab_add(s, "call_arg_list", NULL); symtab_add(s, "join_target_list", NULL); symtab_add(s, "insert_list", NULL); symtab_add(s, "case_list", NULL); symtab_add(s, "update_list", NULL); symtab_add(s, "col_key_list", NULL); symtab_add(s, "cte_binding_list", NULL); // These are list holders, the list isn't interesting, the items are symtab_add(s, "select_core_list", NULL); symtab_add(s, "select_expr_list_con", NULL); symtab_add(s, "select_expr_list", NULL); symtab_add(s, "expr_list", NULL); // These are just wrappers symtab_add(s, "proc_params_stmts", NULL); } cql_noexport void cg_stats_main(struct ast_node *root) { Contract(options.file_names_count == 1); cql_exit_on_semantic_errors(root); exit_on_validating_schema(); cg_stoplist(); CHARBUF_OPEN(output); stats_output = &output; cg_stats_stmt_list(root); cql_write_file(options.file_names[0], output.ptr); CHARBUF_CLOSE(output); stats_output = NULL; symtab_delete(stats_stoplist); stats_stoplist = NULL; } #endif