--- layout: docu title: Prepared Statements --- A prepared statement is a parameterized query. The query is prepared with question marks (`?`) or dollar symbols (`$1`) indicating the parameters of the query. Values can then be bound to these parameters, after which the prepared statement can be executed using those parameters. A single query can be prepared once and executed many times. Prepared statements are useful to: * Easily supply parameters to functions while avoiding string concatenation/SQL injection attacks. * Speeding up queries that will be executed many times with different parameters. DuckDB supports prepared statements in the C API with the `duckdb_prepare` method. The `duckdb_bind` family of functions is used to supply values for subsequent execution of the prepared statement using `duckdb_execute_prepared`. After we are done with the prepared statement it can be cleaned up using the `duckdb_destroy_prepare` method. ## Example ```c duckdb_prepared_statement stmt; duckdb_result result; if (duckdb_prepare(con, "INSERT INTO integers VALUES ($1, $2)", &stmt) == DuckDBError) { // handle error } duckdb_bind_int32(stmt, 1, 42); // the parameter index starts counting at 1! duckdb_bind_int32(stmt, 2, 43); // NULL as second parameter means no result set is requested duckdb_execute_prepared(stmt, NULL); duckdb_destroy_prepare(&stmt); // we can also query result sets using prepared statements if (duckdb_prepare(con, "SELECT * FROM integers WHERE i = ?", &stmt) == DuckDBError) { // handle error } duckdb_bind_int32(stmt, 1, 42); duckdb_execute_prepared(stmt, &result); // do something with result // clean up duckdb_destroy_result(&result); duckdb_destroy_prepare(&stmt); ``` After calling `duckdb_prepare`, the prepared statement parameters can be inspected using `duckdb_nparams` and `duckdb_param_type`. In case the prepare fails, the error can be obtained through `duckdb_prepare_error`. It is not required that the `duckdb_bind` family of functions matches the prepared statement parameter type exactly. The values will be auto-cast to the required value as required. For example, calling `duckdb_bind_int8` on a parameter type of `DUCKDB_TYPE_INTEGER` will work as expected. > Warning Do **not** use prepared statements to insert large amounts of data into DuckDB. Instead it is recommended to use the [Appender]({% link docs/1.3/clients/c/appender.md %}). ## API Reference Overview
duckdb_state duckdb_prepare(duckdb_connection connection, const char *query, duckdb_prepared_statement *out_prepared_statement);
void duckdb_destroy_prepare(duckdb_prepared_statement *prepared_statement);
const char *duckdb_prepare_error(duckdb_prepared_statement prepared_statement);
idx_t duckdb_nparams(duckdb_prepared_statement prepared_statement);
const char *duckdb_parameter_name(duckdb_prepared_statement prepared_statement, idx_t index);
duckdb_type duckdb_param_type(duckdb_prepared_statement prepared_statement, idx_t param_idx);
duckdb_logical_type duckdb_param_logical_type(duckdb_prepared_statement prepared_statement, idx_t param_idx);
duckdb_state duckdb_clear_bindings(duckdb_prepared_statement prepared_statement);
duckdb_statement_type duckdb_prepared_statement_type(duckdb_prepared_statement statement);
duckdb_state duckdb_prepare(
duckdb_connection connection,
const char *query,
duckdb_prepared_statement *out_prepared_statement
);
void duckdb_destroy_prepare(
duckdb_prepared_statement *prepared_statement
);
const char *duckdb_prepare_error(
duckdb_prepared_statement prepared_statement
);
idx_t duckdb_nparams(
duckdb_prepared_statement prepared_statement
);
const char *duckdb_parameter_name(
duckdb_prepared_statement prepared_statement,
idx_t index
);
duckdb_type duckdb_param_type(
duckdb_prepared_statement prepared_statement,
idx_t param_idx
);
duckdb_logical_type duckdb_param_logical_type(
duckdb_prepared_statement prepared_statement,
idx_t param_idx
);
duckdb_state duckdb_clear_bindings(
duckdb_prepared_statement prepared_statement
);
duckdb_statement_type duckdb_prepared_statement_type(
duckdb_prepared_statement statement
);