Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/duckdb/duckdb/llms.txt

Use this file to discover all available pages before exploring further.

The DuckDB C API supports a rich set of data types, from simple integers to complex nested structures.

Type Enumeration

All DuckDB types are represented by the duckdb_type enum (from duckdb.h:61-141):
typedef enum DUCKDB_TYPE {
    DUCKDB_TYPE_INVALID = 0,
    // Numeric types
    DUCKDB_TYPE_BOOLEAN = 1,
    DUCKDB_TYPE_TINYINT = 2,      // int8_t
    DUCKDB_TYPE_SMALLINT = 3,     // int16_t
    DUCKDB_TYPE_INTEGER = 4,      // int32_t
    DUCKDB_TYPE_BIGINT = 5,       // int64_t
    DUCKDB_TYPE_UTINYINT = 6,     // uint8_t
    DUCKDB_TYPE_USMALLINT = 7,    // uint16_t
    DUCKDB_TYPE_UINTEGER = 8,     // uint32_t
    DUCKDB_TYPE_UBIGINT = 9,      // uint64_t
    DUCKDB_TYPE_FLOAT = 10,       // float
    DUCKDB_TYPE_DOUBLE = 11,      // double
    DUCKDB_TYPE_HUGEINT = 16,     // 128-bit integer
    DUCKDB_TYPE_UHUGEINT = 32,    // 128-bit unsigned
    DUCKDB_TYPE_DECIMAL = 19,
    // Temporal types
    DUCKDB_TYPE_DATE = 13,
    DUCKDB_TYPE_TIME = 14,
    DUCKDB_TYPE_TIMESTAMP = 12,
    DUCKDB_TYPE_TIMESTAMP_S = 20,
    DUCKDB_TYPE_TIMESTAMP_MS = 21,
    DUCKDB_TYPE_TIMESTAMP_NS = 22,
    DUCKDB_TYPE_TIMESTAMP_TZ = 31,
    DUCKDB_TYPE_TIME_TZ = 30,
    DUCKDB_TYPE_TIME_NS = 39,
    DUCKDB_TYPE_INTERVAL = 15,
    // String types
    DUCKDB_TYPE_VARCHAR = 17,
    DUCKDB_TYPE_BLOB = 18,
    // Complex types
    DUCKDB_TYPE_LIST = 24,
    DUCKDB_TYPE_STRUCT = 25,
    DUCKDB_TYPE_MAP = 26,
    DUCKDB_TYPE_ARRAY = 33,
    DUCKDB_TYPE_UNION = 28,
    // Special types
    DUCKDB_TYPE_UUID = 27,
    DUCKDB_TYPE_ENUM = 23,
    DUCKDB_TYPE_BIT = 29,
    DUCKDB_TYPE_ANY = 34,
} duckdb_type;

Primitive Types

Boolean

// Create
bool value = true;
duckdb_append_bool(appender, value);

// Read
bool result = duckdb_value_boolean(&result, col, row);

Integer Types

// TINYINT (-128 to 127)
int8_t tiny = -100;
duckdb_append_int8(appender, tiny);
int8_t val = duckdb_value_int8(&result, col, row);

// SMALLINT (-32768 to 32767)
int16_t small = -30000;
duckdb_append_int16(appender, small);

// INTEGER (-2^31 to 2^31-1)
int32_t integer = 1000000;
duckdb_append_int32(appender, integer);

// BIGINT (-2^63 to 2^63-1)
int64_t big = 9223372036854775807LL;
duckdb_append_int64(appender, big);

Floating Point

// FLOAT (32-bit)
float f = 3.14159f;
duckdb_append_float(appender, f);
float fval = duckdb_value_float(&result, col, row);

// DOUBLE (64-bit)
double d = 2.718281828459045;
duckdb_append_double(appender, d);
double dval = duckdb_value_double(&result, col, row);

HUGEINT (128-bit Integer)

typedef struct {
    uint64_t lower;
    int64_t upper;
} duckdb_hugeint;

// Create HUGEINT
duckdb_hugeint huge;
huge.lower = 1000000000ULL;
huge.upper = 5000LL;
duckdb_append_hugeint(appender, huge);

// Read HUGEINT
duckdb_hugeint val = duckdb_value_hugeint(&result, col, row);

// Convert to/from double
double d = duckdb_hugeint_to_double(huge);
duckdb_hugeint huge2 = duckdb_double_to_hugeint(d);

String Types

VARCHAR

// Append string
const char *str = "Hello, DuckDB!";
duckdb_append_varchar(appender, str);

// With explicit length
duckdb_append_varchar_length(appender, "test", 4);

// Read string (must free!)
char *result_str = duckdb_value_varchar(&result, col, row);
printf("%s\n", result_str);
duckdb_free(result_str);

BLOB (Binary Data)

// Create blob
const uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
duckdb_append_blob(appender, data, sizeof(data));

// Read blob
duckdb_blob blob = duckdb_value_blob(&result, col, row);
printf("Blob size: %zu\n", blob.size);
// Process blob.data...
duckdb_free(blob.data);

Temporal Types

DATE

typedef struct {
    int32_t days;  // Days since 1970-01-01
} duckdb_date;

// Create date
duckdb_date date;
date.days = 18628;  // 2021-01-01
duckdb_append_date(appender, date);

// Read date
duckdb_date result_date = duckdb_value_date(&result, col, row);

// Date conversion
duckdb_date_struct parts = duckdb_from_date(date);
printf("%d-%d-%d\n", parts.year, parts.month, parts.day);

duckdb_date reconstructed = duckdb_to_date(parts);

TIME

typedef struct {
    int64_t micros;  // Microseconds since 00:00:00
} duckdb_time;

// Create time
duckdb_time time;
time.micros = 43200000000LL;  // 12:00:00 (noon)
duckdb_append_time(appender, time);

// Time conversion
duckdb_time_struct parts = duckdb_from_time(time);
printf("%02d:%02d:%02d.%06d\n", parts.hour, parts.min, parts.sec, parts.micros);

TIMESTAMP

typedef struct {
    int64_t micros;  // Microseconds since epoch
} duckdb_timestamp;

// Create timestamp
duckdb_timestamp ts;
ts.micros = 1609459200000000LL;  // 2021-01-01 00:00:00 UTC
duckdb_append_timestamp(appender, ts);

// Timestamp conversion
duckdb_timestamp_struct parts = duckdb_from_timestamp(ts);
printf("%d-%02d-%02d %02d:%02d:%02d\n",
       parts.date.year, parts.date.month, parts.date.day,
       parts.time.hour, parts.time.min, parts.time.sec);

INTERVAL

typedef struct {
    int32_t months;
    int32_t days;
    int64_t micros;
} duckdb_interval;

// Create interval: 1 year, 2 months, 3 days, 4 hours
duckdb_interval interval;
interval.months = 14;  // 1 year + 2 months
interval.days = 3;
interval.micros = 4 * 3600 * 1000000LL;  // 4 hours

duckdb_append_interval(appender, interval);

Complex Types

LIST

Lists are variable-length arrays of the same type:
CREATE TABLE lists(id INTEGER, values INTEGER[]);
// Access list elements (simplified)
duckdb_result result;
duckdb_query(con, "SELECT [1, 2, 3, 4, 5]", &result);
// Use duckdb_list_vector_get_child() for detailed access

STRUCT

Structs are fixed-length collections of named fields:
CREATE TABLE structs(id INTEGER, person STRUCT(name VARCHAR, age INTEGER));
// Query struct
duckdb_result result;
duckdb_query(con, "SELECT {'name': 'Alice', 'age': 30}", &result);
// Use duckdb_struct_vector_get_child() for field access

MAP

Maps are key-value pairs:
CREATE TABLE maps(id INTEGER, properties MAP(VARCHAR, INTEGER));

Type Checking

// Get column type
duckdb_type type = duckdb_column_type(&result, col);

switch (type) {
    case DUCKDB_TYPE_INTEGER:
        int32_t ival = duckdb_value_int32(&result, col, row);
        break;
    case DUCKDB_TYPE_VARCHAR:
        char *sval = duckdb_value_varchar(&result, col, row);
        // Use sval...
        duckdb_free(sval);
        break;
    case DUCKDB_TYPE_DOUBLE:
        double dval = duckdb_value_double(&result, col, row);
        break;
    default:
        // Handle other types
        break;
}

NULL Handling

// Check for NULL
if (duckdb_value_is_null(&result, col, row)) {
    printf("Value is NULL\n");
} else {
    // Access value
    int32_t val = duckdb_value_int32(&result, col, row);
}

// Append NULL
duckdb_append_null(appender);

Type Conversion

duckdb_value_varchar() can convert any type to string representation:
// Convert any value to string
char *str = duckdb_value_varchar(&result, col, row);
printf("Value as string: %s\n", str);
duckdb_free(str);

Complete Example

#include "duckdb.h"
#include <stdio.h>

int main() {
    duckdb_database db;
    duckdb_connection con;
    
    duckdb_open(NULL, &db);
    duckdb_connect(db, &con);

    // Create table with various types
    duckdb_query(con, 
        "CREATE TABLE types_demo("
        "  id INTEGER, "
        "  name VARCHAR, "
        "  balance DOUBLE, "
        "  birth_date DATE, "
        "  is_active BOOLEAN, "
        "  data BLOB"
        ")", NULL);

    // Insert using appender
    duckdb_appender appender;
    duckdb_appender_create(con, NULL, "types_demo", &appender);

    // Row 1
    duckdb_append_int32(appender, 1);
    duckdb_append_varchar(appender, "Alice");
    duckdb_append_double(appender, 1234.56);
    duckdb_date date;
    date.days = 18628;
    duckdb_append_date(appender, date);
    duckdb_append_bool(appender, true);
    uint8_t blob_data[] = {0xDE, 0xAD, 0xBE, 0xEF};
    duckdb_append_blob(appender, blob_data, sizeof(blob_data));
    duckdb_appender_end_row(appender);

    duckdb_appender_close(appender);

    // Query and print
    duckdb_result result;
    if (duckdb_query(con, "SELECT * FROM types_demo", &result) == DuckDBSuccess) {
        idx_t cols = duckdb_column_count(&result);
        
        // Print column types
        for (idx_t i = 0; i < cols; i++) {
            printf("%s (%d)\t", 
                   duckdb_column_name(&result, i),
                   duckdb_column_type(&result, i));
        }
        printf("\n");

        duckdb_destroy_result(&result);
    }

    duckdb_disconnect(&con);
    duckdb_close(&db);
    return 0;
}

Next Steps

C Examples

See complete working code

C++ API

Explore the C++ API