in sources/cg_schema.c [903:1045]
static void cg_schema_manage_indices(charbuf *output, int32_t *drops, int32_t *creates) {
Contract(creates);
Contract(drops);
CHARBUF_OPEN(create);
CHARBUF_OPEN(drop);
CHARBUF_OPEN(names);
// non-null-callbacks will generate SQL for Sqlite (no attributes)
gen_sql_callbacks callbacks;
init_gen_sql_callbacks(&callbacks);
callbacks.mode = gen_mode_no_annotations;
*drops = *creates = 0;
for (list_item *item = all_indices_list; item; item = item->next) {
ast_node *ast = item->ast;
Invariant(is_ast_create_index_stmt(ast));
if (!include_from_region(ast->sem->region, SCHEMA_TO_UPGRADE)) {
continue;
}
Contract(is_ast_create_index_stmt(ast));
EXTRACT_NOTNULL(create_index_on_list, ast->left);
EXTRACT_NOTNULL(flags_names_attrs, ast->right);
EXTRACT_NOTNULL(connector, flags_names_attrs->right);
EXTRACT_NOTNULL(index_names_and_attrs, connector->left);
EXTRACT_NOTNULL(indexed_columns, index_names_and_attrs->left);
EXTRACT(opt_where, index_names_and_attrs->right);
EXTRACT_ANY_NOTNULL(index_name_ast, create_index_on_list->left);
EXTRACT_STRING(index_name, index_name_ast);
EXTRACT_ANY_NOTNULL(table_name_ast, create_index_on_list->right);
EXTRACT_STRING(table_name, table_name_ast);
if (names.used > 1) {
bprintf(&names, ",\n '%s'", index_name);
}
else {
bprintf(&names, "\n '%s'", index_name);
}
if (ast->sem->delete_version > 0) {
// delete only, we're done here
bprintf(&drop, " DROP INDEX IF EXISTS %s;\n", index_name);
(*drops)++;
continue;
}
// If this index is attached to a table marked @recreate then we recreate the index with the table
// as a unit so there is nothing to do here. The index will be in the same @recreate group as
// the table if it has one.
ast_node *table_ast = find_table_or_view_even_deleted(table_name);
Invariant(table_ast);
Invariant(table_ast->sem);
if (table_ast->sem->recreate) {
// recreate table ... skip it as above.
continue;
}
// drop then recreate after other migrate steps
CHARBUF_OPEN(make_index);
gen_set_output_buffer(&make_index);
gen_statement_with_callbacks(ast, &callbacks);
bprintf(&make_index, ";\n");
llint_t index_crc = (llint_t)crc_charbuf(&make_index);
bprintf(&drop, " IF cql_facet_find(%s_facets, '%s_index_crc') != %lld THEN\n", global_proc_name, index_name, index_crc);
bprintf(&drop, " DROP INDEX IF EXISTS %s;\n", index_name);
bprintf(&drop, " END IF;\n");
bprintf(&create, " IF cql_facet_find(%s_facets, '%s_index_crc') != %lld THEN\n", global_proc_name, index_name, index_crc);
bindent(&create, &make_index, 4);
bprintf(&create, " CALL %s_cql_set_facet_version('%s_index_crc', %lld);\n", global_proc_name, index_name, index_crc);
bprintf(&create, " END IF;\n");
CHARBUF_CLOSE(make_index);
// we always have a mutation plan for potentially changed indices so
// that means there is a drop and a create
(*creates)++;
(*drops)++;
}
if (options.schema_exclusive) {
bprintf(output, "\n-- get all the unknown index names, store them in a result set\n");
bprintf(output, "@attribute(cql:private)\n");
bprintf(output, "CREATE PROCEDURE %s_cql_get_unknown_indices()\n", global_proc_name);
bprintf(output, "BEGIN\n");
bprintf(output, " DECLARE C CURSOR FOR SELECT name from sqlite_master where type = 'index'\n");
bprintf(output, " AND name NOT LIKE 'sqlite%%'", names.ptr);
if (names.used > 1) {
bprintf(output, "\n AND name NOT IN (%s)", names.ptr);
}
bprintf(output, ";\n");
bprintf(output, " LOOP FETCH C\n");
bprintf(output, " BEGIN\n");
bprintf(output, " OUT UNION C;\n");
bprintf(output, " END;\n");
bprintf(output, "END;\n\n");
bprintf(output, "-- drop all the indices using the fetched names\n");
bprintf(output, "@attribute(cql:private)\n");
bprintf(output, "CREATE PROCEDURE %s_cql_drop_unknown_indices()\n", global_proc_name);
bprintf(output, "BEGIN\n");
bprintf(output, " DECLARE C CURSOR FOR CALL %s_cql_get_unknown_indices();\n", global_proc_name);
bprintf(output, " LOOP FETCH C\n");
bprintf(output, " BEGIN\n");
bprintf(output, " CALL cql_exec_internal(printf('DROP INDEX %%s;', C.name));\n");
bprintf(output, " END;\n");
bprintf(output, "END;\n\n");
bprintf(&drop, " CALL %s_cql_drop_unknown_indices();\n", global_proc_name);
// we always behave as though we have some drops in exclusive mode
*drops = 1;
}
if (*drops) {
bprintf(output, "-- drop all the indices that are deleted or changing\n");
bprintf(output, "@attribute(cql:private)\n");
bprintf(output, "CREATE PROCEDURE %s_cql_drop_all_indices()\n", global_proc_name);
bprintf(output, "BEGIN\n");
bprintf(output, "%s", drop.ptr);
bprintf(output, "END;\n\n");
}
if (*creates) {
bprintf(output, "-- create all the indices we need\n");
bprintf(output, "@attribute(cql:private)\n");
bprintf(output, "CREATE PROCEDURE %s_cql_create_all_indices()\n", global_proc_name);
bprintf(output, "BEGIN\n");
bprintf(output, "%s", create.ptr);
bprintf(output, "END;\n\n");
}
CHARBUF_CLOSE(names);
CHARBUF_CLOSE(drop);
CHARBUF_CLOSE(create);
}