static void cg_bound_sql_statement()

in sources/cg_c.c [4811:4971]


static void cg_bound_sql_statement(CSTR stmt_name, ast_node *stmt, int32_t cg_flags) {
  list_item *vars = NULL;
  CSTR amp = "&";

  cur_bound_statement++;
  cur_fragment_predicate = 0;
  max_fragment_predicate = 0;
  prev_variable_count = 0;
  cur_variable_count = 0;

  bytebuf_open(&shared_fragment_strings);

  if (stmt_name && !strcmp("_result", stmt_name)) {
    // predefined out argument
    amp = "";
  }

  cg_classify_fragments(stmt);

  if (has_conditional_fragments) {
    bprintf(cg_main_output, "memset(&_preds_%d[0], 0, sizeof(_preds_%d));\n",
      cur_bound_statement,
      cur_bound_statement);
    if (has_variables) {
      bprintf(cg_main_output, "memset(&_vpreds_%d[0], 0, sizeof(_vpreds_%d));\n",
        cur_bound_statement,
        cur_bound_statement);
    }
  }

  bool_t minify_aliases = !!(cg_flags & CG_MINIFY_ALIASES);
  bool_t exec_only = !!(cg_flags & CG_EXEC);

  gen_sql_callbacks callbacks;
  init_gen_sql_callbacks(&callbacks);
  callbacks.variables_callback = cg_capture_variables;
  callbacks.variables_context = &vars;
  callbacks.star_callback = cg_expand_star;
  callbacks.minify_casts = 1;
  callbacks.minify_aliases = minify_aliases;
  callbacks.long_to_int_conv = true;
  callbacks.cte_proc_callback = cg_call_in_cte;
  callbacks.cte_suppress_callback = cg_suppress_cte;
  callbacks.table_rename_callback = cg_table_rename;
  callbacks.inline_func_callback = cg_inline_func;

  CHARBUF_OPEN(temp);
  gen_set_output_buffer(&temp);
  gen_statement_with_callbacks(stmt, &callbacks);

  // whether or not there is a prepare statement
  bool_t has_prepare_stmt = !exec_only || vars;

  uint32_t count = 0;
  for (list_item *item = vars; item; item = item->next, count++) ;

  if (stmt_name == NULL && has_prepare_stmt) {
    ensure_temp_statement();
    stmt_name = "_temp";
  }

  // take care of what's left in the buffer after the other fragments have been emitted
  if (has_shared_fragments) {
    cg_emit_one_frag(&temp);
  }

  if (!has_shared_fragments && options.compress) {
    bprintf(cg_main_output, "/*  ");
    CHARBUF_OPEN(t2);
      cg_pretty_quote_plaintext(temp.ptr, &t2, PRETTY_QUOTE_C | PRETTY_QUOTE_MULTI_LINE);
      cg_remove_slash_star_and_star_slash(&t2); // internal "*/" is fatal. "/*" can also be under certain compilation flags
      bprintf(cg_main_output, "%s", t2.ptr);
    CHARBUF_CLOSE(t2);
    bprintf(cg_main_output, " */\n");

    if (!has_prepare_stmt) {
      bprintf(cg_main_output, "_rc_ = cql_exec_frags(_db_,\n");
    }
    else {
      bprintf(cg_main_output, "_rc_ = cql_prepare_frags(_db_, %s%s_stmt,\n  ", amp, stmt_name);
    }

    bprintf(cg_main_output, "_pieces_, ");
    cg_statement_pieces(temp.ptr, cg_main_output);
    bprintf(cg_main_output, ");\n");
  }
  else {
    CSTR suffix = has_shared_fragments ? "_var" : "";

    if (!has_prepare_stmt) {
      bprintf(cg_main_output, "_rc_ = cql_exec%s(_db_,\n  ", suffix);
    }
    else {
      bprintf(cg_main_output, "_rc_ = cql_prepare%s(_db_, %s%s_stmt,\n  ", suffix, amp, stmt_name);
    }

    if (!has_shared_fragments) {
      cg_pretty_quote_plaintext(temp.ptr, cg_main_output, PRETTY_QUOTE_C | PRETTY_QUOTE_MULTI_LINE);
    }
    else {
      int32_t scount = cg_fragment_count();

      // declare the predicate variables if needed
      if (has_conditional_fragments) {
        bprintf(cg_main_output, "%d, _preds_%d,\n", scount, cur_bound_statement);
        bprintf(cg_declarations_output, "char _preds_%d[%d];\n", cur_bound_statement, scount);
        if (has_variables) {
          bprintf(cg_declarations_output, "char _vpreds_%d[%d];\n", cur_bound_statement, cur_variable_count);
        }
      }
      else {
        bprintf(cg_main_output, "%d, NULL,\n", scount);
      }

      CSTR *strs = (CSTR *)(shared_fragment_strings.ptr);
      for (size_t i = 0; i < scount; i++) {
        cg_pretty_quote_plaintext(strs[i], cg_main_output, PRETTY_QUOTE_C | PRETTY_QUOTE_MULTI_LINE);
        if (i + 1 < scount) {
          bprintf(cg_main_output, ",\n");
        }
        else {
          bprintf(cg_main_output, "\n");
        }
      }
    }
    bprintf(cg_main_output, ");\n");
  }

  CHARBUF_CLOSE(temp);

  reverse_list(&vars);

  if (count) {
    if (has_conditional_fragments) {
      bprintf(cg_main_output, "cql_multibind_var(&_rc_, _db_, %s%s_stmt, %d, _vpreds_%d", amp, stmt_name, count, cur_bound_statement);
    }
    else {
      bprintf(cg_main_output, "cql_multibind(&_rc_, _db_, %s%s_stmt, %d", amp, stmt_name, count);
    }

    // Now emit the binding args for each variable
    for (list_item *item = vars; item; item = item->next)  {
      Contract(item->ast->sem->name);
      bprintf(cg_main_output, ",\n              ");
      cg_bind_column(item->ast->sem->sem_type, item->ast->sem->name);
    }

    bprintf(cg_main_output, ");\n");
  }

  cg_error_on_not_sqlite_ok();

  if (exec_only && vars) {
    bprintf(cg_main_output, "_rc_ = sqlite3_step(%s_stmt);\n", stmt_name);
    cg_error_on_rc_notequal("SQLITE_DONE");
    bprintf(cg_main_output, "cql_finalize_stmt(&%s_stmt);\n", stmt_name);
  }

  // vars is pool allocated, so we don't need to free it
  bytebuf_close(&shared_fragment_strings);
}