static void cg_generate_schema_by_mode()

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");
      }
    }
  }
}