duckdb clib

DuckDB embedded OLAP SQL — blazing-fast columnar analytics directly on CSV, Parquet, and JSON files without any import step.

ppm install duckdb
System dependency: download libduckdb.so from duckdb.org (no apt package for latest version)

Overview

DuckDB is the “SQLite of analytics”. It executes SQL with columnar vectorized execution across all CPU cores, directly on CSV, Parquet, and JSON files — no server, no import step, just query. Results from a 100 M-row Parquet file arrive in seconds from a laptop. It is used by data engineers, ML pipelines, and BI tools everywhere that high-speed aggregation over flat files matters.

Unlike SQLite (row-oriented, optimized for OLTP), DuckDB is column-oriented and optimized for analytical queries: GROUP BY, aggregations, window functions, and joins over millions of rows. Both can coexist in the same program — use SQLite for transactional state, DuckDB for analytics.

Query a CSV File Directly

uses duckdb;

var db := OpenMemory();

// DuckDB reads CSV on disk; no IMPORT or COPY needed
var rows := Query(db,
  'SELECT region, SUM(sales) AS total ' +
  'FROM ''sales.csv'' ' +
  'GROUP BY region ORDER BY 2 DESC');

for var r in rows do
  WriteLn(r['region'], '  $', r['total']);

Close(db);

In-Memory Analytics with Window Functions

uses duckdb;

var db := OpenMemory();

// Create an in-memory table from a Parquet file
Execute(db,
  'CREATE TABLE events AS SELECT * FROM read_parquet(''events.parquet'')');

// Window function: running total per user
var rows := Query(db,
  'SELECT user_id, ts, amount, ' +
  'SUM(amount) OVER (PARTITION BY user_id ORDER BY ts) AS running_total ' +
  'FROM events ORDER BY user_id, ts');

for var r in rows do
  WriteLn(r['user_id'], '  ', r['running_total']);

Close(db);

Prepared Statements

uses duckdb;

var db := Open('analytics.db');

// Prepare once, execute many times with $1 $2 positional parameters
var stmt := Prepare(db, 'SELECT * FROM orders WHERE status = $1 AND year = $2');

BindText(stmt, 1, 'shipped');
BindInt(stmt, 2, 2024);
var rows := ExecuteStmt(stmt);

for var r in rows do
  WriteLn(r['order_id'], '  ', r['amount']);

ResetStmt(stmt);
FinalizeStmt(stmt);
Close(db);

Export to Parquet

uses duckdb;

var db := OpenMemory();

// Query across JSON + CSV and export result as Parquet in one call
ExportParquet(db,
  'SELECT a.user_id, a.name, b.total_spend ' +
  'FROM read_json_auto(''users.json'') a ' +
  'JOIN read_csv_auto(''spend.csv'') b ON a.user_id = b.user_id',
  '/out/enriched_users.parquet');

WriteLn('Exported.');
Close(db);

API Reference

Open / Close

FunctionDescription
Open(path)Open or create a persistent DuckDB database file; returns a db handle
OpenMemory()Open an in-memory DuckDB instance; data is lost on Close
Close(db)Flush and release all resources for a db handle

Execute & Query

FunctionDescription
Execute(db, sql)Run a DDL or DML statement with no result set (CREATE, INSERT, UPDATE, DELETE)
Query(db, sql)Run a SELECT and return a List of row dictionaries (column name → value)
QueryScalar(db, sql)Run a single-value SELECT and return the result as a Variant
QueryInt(db, sql)Run a single-value SELECT and return an Integer
QueryFloat(db, sql)Run a single-value SELECT and return a Float

Prepared Statements

FunctionDescription
Prepare(db, sql)Compile a parameterized SQL string into a reusable statement handle
BindInt(stmt, idx, val)Bind an Integer to positional parameter $idx (1-based)
BindFloat(stmt, idx, val)Bind a Float to positional parameter $idx
BindText(stmt, idx, val)Bind a String to positional parameter $idx
BindBool(stmt, idx, val)Bind a Boolean to positional parameter $idx
BindNull(stmt, idx)Bind SQL NULL to positional parameter $idx
ExecuteStmt(stmt)Execute a prepared statement and return the result rows
ResetStmt(stmt)Reset bindings so the statement can be reused with new parameters
FinalizeStmt(stmt)Release a prepared statement handle

File Queries

FunctionDescription
QueryCSV(db, path, sql)Register a CSV file as a virtual table and run sql against it
QueryParquet(db, path, sql)Register a Parquet file as a virtual table and run sql
QueryJSON(db, path, sql)Register a JSON/NDJSON file as a virtual table and run sql
ImportCSV(db, path, table)Load a CSV file into a named in-memory table
ExportCSV(db, sql, path)Execute sql and write the result set as a CSV file
ExportParquet(db, sql, path)Execute sql and write the result set as a Parquet file

Transactions

FunctionDescription
BeginTransaction(db)Begin an explicit transaction (auto-commit is on by default)
Commit(db)Commit the current transaction
Rollback(db)Rollback the current transaction and discard all changes

Schema Inspection

FunctionDescription
GetTables(db)Return a List of table names in the current database
GetColumns(db, table)Return a List of TColumnInfo (Name, Type, Nullable) for a table
TableExists(db, table)True if the named table exists in the current database

Configuration

FunctionDescription
SetThreads(db, n)Set the number of worker threads used for parallel query execution
SetMemoryLimit(db, bytes)Cap the maximum memory DuckDB may allocate for a query (e.g. 2*1024*1024*1024 for 2 GB)