--- layout: docu title: Query --- The `duckdb_query` method allows SQL queries to be run in DuckDB from C. This method takes two parameters, a (null-terminated) SQL query string and a `duckdb_result` result pointer. The result pointer may be `NULL` if the application is not interested in the result set or if the query produces no result. After the result is consumed, the `duckdb_destroy_result` method should be used to clean up the result. Elements can be extracted from the `duckdb_result` object using a variety of methods. The `duckdb_column_count` can be used to extract the number of columns. `duckdb_column_name` and `duckdb_column_type` can be used to extract the names and types of individual columns. ## Example ```c duckdb_state state; duckdb_result result; // create a table state = duckdb_query(con, "CREATE TABLE integers (i INTEGER, j INTEGER);", NULL); if (state == DuckDBError) { // handle error } // insert three rows into the table state = duckdb_query(con, "INSERT INTO integers VALUES (3, 4), (5, 6), (7, NULL);", NULL); if (state == DuckDBError) { // handle error } // query rows again state = duckdb_query(con, "SELECT * FROM integers", &result); if (state == DuckDBError) { // handle error } // handle the result // ... // destroy the result after we are done with it duckdb_destroy_result(&result); ``` ## Value Extraction Values can be extracted using either the `duckdb_fetch_chunk` function, or using the `duckdb_value` convenience functions. The `duckdb_fetch_chunk` function directly hands you data chunks in DuckDB's native array format and can therefore be very fast. The `duckdb_value` functions perform bounds- and type-checking, and will automatically cast values to the desired type. This makes them more convenient and easier to use, at the expense of being slower. See the [Types]({% link docs/1.3/clients/c/types.md %}) page for more information. > For optimal performance, use `duckdb_fetch_chunk` to extract data from the query result. > The `duckdb_value` functions perform internal type-checking, bounds-checking and casting which makes them slower. ### `duckdb_fetch_chunk` Below is an end-to-end example that prints the above result to CSV format using the `duckdb_fetch_chunk` function. Note that the function is NOT generic: we do need to know exactly what the types of the result columns are. ```c duckdb_database db; duckdb_connection con; duckdb_open(nullptr, &db); duckdb_connect(db, &con); duckdb_result res; duckdb_query(con, "CREATE TABLE integers (i INTEGER, j INTEGER);", NULL); duckdb_query(con, "INSERT INTO integers VALUES (3, 4), (5, 6), (7, NULL);", NULL); duckdb_query(con, "SELECT * FROM integers;", &res); // iterate until result is exhausted while (true) { duckdb_data_chunk result = duckdb_fetch_chunk(res); if (!result) { // result is exhausted break; } // get the number of rows from the data chunk idx_t row_count = duckdb_data_chunk_get_size(result); // get the first column duckdb_vector col1 = duckdb_data_chunk_get_vector(result, 0); int32_t *col1_data = (int32_t *) duckdb_vector_get_data(col1); uint64_t *col1_validity = duckdb_vector_get_validity(col1); // get the second column duckdb_vector col2 = duckdb_data_chunk_get_vector(result, 1); int32_t *col2_data = (int32_t *) duckdb_vector_get_data(col2); uint64_t *col2_validity = duckdb_vector_get_validity(col2); // iterate over the rows for (idx_t row = 0; row < row_count; row++) { if (duckdb_validity_row_is_valid(col1_validity, row)) { printf("%d", col1_data[row]); } else { printf("NULL"); } printf(","); if (duckdb_validity_row_is_valid(col2_validity, row)) { printf("%d", col2_data[row]); } else { printf("NULL"); } printf("\n"); } duckdb_destroy_data_chunk(&result); } // clean-up duckdb_destroy_result(&res); duckdb_disconnect(&con); duckdb_close(&db); ``` This prints the following result: ```csv 3,4 5,6 7,NULL ``` ### `duckdb_value` > Deprecated The `duckdb_value` functions are deprecated and are scheduled for removal in a future release. Below is an example that prints the above result to CSV format using the `duckdb_value_varchar` function. Note that the function is generic: we do not need to know about the types of the individual result columns. ```c // print the above result to CSV format using `duckdb_value_varchar` idx_t row_count = duckdb_row_count(&result); idx_t column_count = duckdb_column_count(&result); for (idx_t row = 0; row < row_count; row++) { for (idx_t col = 0; col < column_count; col++) { if (col > 0) printf(","); auto str_val = duckdb_value_varchar(&result, col, row); printf("%s", str_val); duckdb_free(str_val); } printf("\n"); } ``` ## API Reference Overview
duckdb_state duckdb_query(duckdb_connection connection, const char *query, duckdb_result *out_result);
void duckdb_destroy_result(duckdb_result *result);
const char *duckdb_column_name(duckdb_result *result, idx_t col);
duckdb_type duckdb_column_type(duckdb_result *result, idx_t col);
duckdb_statement_type duckdb_result_statement_type(duckdb_result result);
duckdb_logical_type duckdb_column_logical_type(duckdb_result *result, idx_t col);
idx_t duckdb_column_count(duckdb_result *result);
idx_t duckdb_row_count(duckdb_result *result);
idx_t duckdb_rows_changed(duckdb_result *result);
void *duckdb_column_data(duckdb_result *result, idx_t col);
bool *duckdb_nullmask_data(duckdb_result *result, idx_t col);
const char *duckdb_result_error(duckdb_result *result);
duckdb_error_type duckdb_result_error_type(duckdb_result *result);
duckdb_state duckdb_query(
duckdb_connection connection,
const char *query,
duckdb_result *out_result
);
void duckdb_destroy_result(
duckdb_result *result
);
const char *duckdb_column_name(
duckdb_result *result,
idx_t col
);
duckdb_type duckdb_column_type(
duckdb_result *result,
idx_t col
);
duckdb_statement_type duckdb_result_statement_type(
duckdb_result result
);
duckdb_logical_type duckdb_column_logical_type(
duckdb_result *result,
idx_t col
);
idx_t duckdb_column_count(
duckdb_result *result
);
idx_t duckdb_row_count(
duckdb_result *result
);
idx_t duckdb_rows_changed(
duckdb_result *result
);
void *duckdb_column_data(
duckdb_result *result,
idx_t col
);
bool *duckdb_nullmask_data(
duckdb_result *result,
idx_t col
);
const char *duckdb_result_error(
duckdb_result *result
);
duckdb_error_type duckdb_result_error_type(
duckdb_result *result
);