in sources/cg_schema.c [446:689]
static void cg_generate_schema_by_mode(charbuf *output, int32_t mode) {
// 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;
// If the mode is SCHEMA_TO_DECLARE then we include all the regions we are upgrading
// and all their dependencies. We do not exclude things that are upgraded elsewhere.
// We do this because we need a logically consistent set of declarations.
// If the mode is SCHEMA_TO_UPGRADE then we include the above but we reject
// anything on the exclude list. That list corresponds to things that are upgraded
// elsewhere. Here we do not need schema that has consistent declarations but rather
// canonical schema that we can checksum for changes. SCHEMA_TO_UPGRADE won't compile
// because it's missing dependencies.
// If the mode includes SCHEMA_TEMP_ITEMS then we emit only temp items
// otherwise we emit only NON temp items.
bool_t temp_required = !!(mode & SCHEMA_TEMP_ITEMS);
bool_t schema_declare = !!(mode & SCHEMA_TO_DECLARE);
bool_t schema_upgrade = !!(mode & SCHEMA_TO_UPGRADE);
bool_t schema_sqlite = !!(mode & SCHEMA_FOR_SQLITE);
gen_sql_callbacks *use_callbacks = NULL;
// full annotations for declarations, no annotations for temp items upgrade
if (temp_required && schema_upgrade) {
use_callbacks = &callbacks;
}
// sqlite form gets sqlite safe output
if (schema_sqlite) {
use_callbacks = &callbacks;
callbacks.mode = gen_mode_sql;
callbacks.long_to_int_conv = true;
}
// emit all the delare select function statements (they may appear in the SQL)
if (!temp_required && schema_declare) {
// select functions are never temp, they go in the main phase
// we never upgrade them, so they don't go in the upgrade section only the declare section
// they appear in the previous section and the normal section so on previous validation
// runs the same declaration will be duplicated. That's ok, we're tolerant to that now.
for (list_item *item = all_select_functions_list; item; item = item->next) {
ast_node *ast = item->ast;
Contract(is_ast_declare_select_func_stmt(ast));
gen_set_output_buffer(output);
gen_statement_with_callbacks(ast, use_callbacks);
bprintf(output, ";\n\n");
}
for (list_item *item = all_regions_list; item; item = item->next) {
ast_node *ast = item->ast;
Contract(is_ast_declare_schema_region_stmt(ast) || is_ast_declare_deployable_region_stmt(ast));
gen_set_output_buffer(output);
gen_statement_with_callbacks(ast, use_callbacks);
bprintf(output, ";\n\n");
}
}
// emit all tables
for (list_item *item = all_tables_list; item; item = item->next) {
ast_node *ast = item->ast;
ast_node *ast_output = ast;
if (is_virtual_ast(ast)) {
ast_output = ast->parent;
Invariant(is_ast_create_virtual_table_stmt(ast_output));
}
Invariant(is_ast_create_table_stmt(ast));
// Note that we do not filter out blob_storage tables universally, their type might be mentioned
// as part of the type descriminator in other parts of schema, so the declaration will stay.
// They will get the usual region treatment for dependencies. However, in no case will
// SQLite ever see these tables.
if (schema_sqlite && is_table_blob_storage(ast)) {
continue;
}
CSTR region = ast->sem->region;
if (!include_from_region(region, mode)) {
continue;
}
EXTRACT_NOTNULL(create_table_name_flags, ast->left);
EXTRACT_NOTNULL(table_flags_attrs, create_table_name_flags->left);
EXTRACT_OPTION(flags, table_flags_attrs->left);
bool_t temp = !!(flags & TABLE_IS_TEMP);
if (temp != temp_required) {
continue;
}
if (region && schema_declare) {
bprintf(output, "@begin_schema_region %s;\n", region);
}
gen_set_output_buffer(output);
gen_statement_with_callbacks(ast_output, use_callbacks);
bprintf(output, ";\n");
if (region && schema_declare) {
bprintf(output, "@end_schema_region;\n");
}
bprintf(output, "\n");
}
for (list_item *item = all_views_list; item; item = item->next) {
ast_node *ast = item->ast;
Invariant(is_ast_create_view_stmt(ast));
CSTR region = ast->sem->region;
if (!include_from_region(region, mode)) {
continue;
}
EXTRACT_OPTION(flags, ast->left);
bool_t temp = !!(flags & VIEW_IS_TEMP);
if (temp != temp_required) {
continue;
}
if (region && schema_declare) {
bprintf(output, "@begin_schema_region %s;\n", region);
}
gen_set_output_buffer(output);
gen_statement_with_callbacks(ast, use_callbacks);
bprintf(output, ";\n");
if (region && schema_declare) {
bprintf(output, "@end_schema_region;\n");
}
bprintf(output, "\n");
}
// Indices are never TEMP in Sqlite, so if temp required then skip entirely
if (!temp_required) {
for (list_item *item = all_indices_list; item; item = item->next) {
ast_node *ast = item->ast;
Invariant(is_ast_create_index_stmt(ast));
CSTR region = ast->sem->region;
if (!include_from_region(region, mode)) {
continue;
}
if (region && schema_declare) {
bprintf(output, "@begin_schema_region %s;\n", region);
}
gen_set_output_buffer(output);
gen_statement_with_callbacks(ast, use_callbacks);
bprintf(output, ";\n");
if (region && schema_declare) {
bprintf(output, "@end_schema_region;\n");
}
bprintf(output, "\n");
}
}
for (list_item *item = all_triggers_list; item; item = item->next) {
ast_node *ast = item->ast;
Invariant(is_ast_create_trigger_stmt(ast));
CSTR region = ast->sem->region;
if (!include_from_region(region, mode)) {
continue;
}
EXTRACT_OPTION(flags, ast->left);
bool_t temp = !!(flags & TRIGGER_IS_TEMP);
if (temp != temp_required) {
continue;
}
if (region && schema_declare) {
bprintf(output, "@begin_schema_region %s;\n", region);
}
gen_set_output_buffer(output);
gen_statement_with_callbacks(ast, use_callbacks);
bprintf(output, ";\n");
if (region && schema_declare) {
bprintf(output, "@end_schema_region;\n");
}
bprintf(output, "\n");
}
// there are no "temp" migrations, so don't emit these at all if "temp required" is set
// likewise if the output is for sqlite these are not processed by sqlite so they should be ignored
if (!temp_required && !schema_sqlite) {
for (list_item *item = all_ad_hoc_list; item; item = item->next) {
ast_node *ast = item->ast;
Invariant(is_ast_schema_ad_hoc_migration_stmt(ast));
CSTR region = ast->sem->region;
if (!include_from_region(region, mode)) {
continue;
}
if (region && schema_declare) {
bprintf(output, "@begin_schema_region %s;\n", region);
}
gen_set_output_buffer(output);
gen_statement_with_callbacks(ast, use_callbacks);
bprintf(output, ";\n");
if (region && schema_declare) {
bprintf(output, "@end_schema_region;\n");
}
bprintf(output, "\n");
}
}
// there are no "temp" unsub/resub, so don't emit these at all if "temp required" is set
// likewise if the output is for sqlite these are not processed by sqlite so they should be ignored
if (!temp_required && !schema_sqlite) {
for (list_item *item = all_subscriptions_list; item; item = item->next) {
ast_node *ast = item->ast;
Invariant(is_ast_schema_unsub_stmt(ast) || is_ast_schema_resub_stmt(ast));
// the node gets is region from its target, not from its own region
CSTR region = ast->sem->region;
if (include_from_region(region, mode)) {
gen_set_output_buffer(output);
gen_statement_with_callbacks(ast, use_callbacks);
bprintf(output, ";\n\n");
}
}
}
}