- Installation
- What's New in the Docs for 2.0
- Documentation
- Getting Started
- Connect
- Data Import and Export
- Overview
- Data Sources
- CSV Files
- IO
- JSON Files
- Overview
- Creating JSON
- Loading JSON
- Writing JSON
- JSON Type
- JSON Functions
- Format Settings
- Installing and Loading
- SQL to / from JSON
- Caveats
- Multiple Files
- Parquet Files
- Partitioning
- Appender
- INSERT Statements
- Lakehouse Formats
- Client APIs
- Overview
- ADBC
- C
- Overview
- Startup
- Configuration
- Query
- Data Chunks
- Vectors
- Values
- Types
- Prepared Statements
- Appender
- Table Functions
- Replacement Scans
- API Reference
- C++
- CLI
- Overview
- Arguments
- Dot Commands
- Output Formats
- Agent Mode
- Editing
- Friendly CLI
- Safe Mode
- Autocomplete
- Syntax Highlighting
- Known Issues
- Go
- Overview
- Connect
- Import Data
- Run Queries
- Handle Results
- Write User Defined Functions
- Profile and Monitor
- Troubleshoot
- Java (JDBC)
- Overview
- Connect
- Import Data
- Run Queries
- Handle Results
- Write User Defined Functions
- Profile and Monitor
- Deploy as Native Image
- Troubleshoot
- Node.js (Neo)
- ODBC
- Python
- Overview
- Data Ingestion
- Appender
- Conversion between DuckDB and Python
- DB API
- Relational API
- Function API
- Types API
- Expression API
- Spark API
- API Reference
- Known Python Issues
- Migrating to 2.0
- R
- Rust
- Overview
- Connect
- Import Data
- Run Queries
- Handle Results
- Write User Defined Functions
- Profile and Monitor
- Troubleshoot
- Wasm
- Tertiary Clients
- SQL
- Introduction
- Statements
- Overview
- ANALYZE
- ALTER DATABASE
- ALTER TABLE
- ALTER VIEW
- ATTACH and DETACH
- CALL
- CHECKPOINT
- COMMENT ON
- CONNECT and DISCONNECT
- COPY
- CREATE INDEX
- CREATE MACRO
- CREATE SCHEMA
- CREATE SECRET
- CREATE SEQUENCE
- CREATE TABLE
- CREATE VIEW
- CREATE TRIGGER
- CREATE TYPE
- DELETE
- DESCRIBE
- DROP
- EXPORT and IMPORT DATABASE
- INSERT
- LOAD / INSTALL
- MERGE INTO
- PIVOT
- Profiling
- PREPARE, EXECUTE, and DEALLOCATE
- SELECT
- SET / RESET
- SET VARIABLE
- SHOW and SHOW DATABASES
- SUMMARIZE
- Transaction Management
- UNPIVOT
- UPDATE
- UPDATE EXTENSIONS
- USE
- VACUUM
- Query Syntax
- SELECT
- FROM and JOIN
- WHERE
- GROUP BY
- GROUPING SETS
- HAVING
- ORDER BY
- LIMIT and OFFSET
- SAMPLE
- Unnesting
- WITH
- WINDOW
- QUALIFY
- VALUES
- FILTER
- Set Operations
- Prepared Statements
- Data Types
- Overview
- Array
- Bitstring
- Blob
- Boolean
- Date
- Enum
- Geometry
- Interval
- List
- Literal Types
- Map
- NULL Values
- Numeric
- Struct
- Text
- Time
- Timestamp
- Time Zones
- Union
- Typecasting
- Variant
- Expressions
- Overview
- CASE Expression
- Casting
- Collations
- Comparisons
- IN Operator
- Logical Operators
- Star Expression
- Subqueries
- TRY
- Functions
- Overview
- Aggregate Functions
- Array Functions
- Bitstring Functions
- Blob Functions
- Date Format Functions
- Date Functions
- Date Part Functions
- Enum Functions
- Geometry Functions
- Interval Functions
- Lambda Functions
- List Functions
- Map Functions
- Nested Functions
- Numeric Functions
- Pattern Matching
- Regular Expressions
- Struct Functions
- Text Functions
- Time Functions
- Timestamp Functions
- Timestamp with Time Zone Functions
- Union Functions
- Utility Functions
- Variant Functions
- Window Functions
- Constraints
- Indexes
- Meta Queries
- DuckDB's SQL Dialect
- Overview
- Indexing
- Friendly SQL
- Keywords and Identifiers
- Order Preservation
- PostgreSQL Compatibility
- SQL Quirks
- PEG Parser
- Samples
- Configuration
- Extensions
- Overview
- Installing Extensions
- Advanced Installation Methods
- Distributing Extensions
- Extension Repositories
- Community Extensions
- Versioning of Extensions
- Troubleshooting of Extensions
- Core Extensions
- Overview
- AutoComplete
- Avro
- AWS
- Azure
- Delta
- DuckLake
- Encodings
- Excel
- Full Text Search
- httpfs (HTTP and S3)
- Overview
- HTTP(S) Support
- Hugging Face
- S3 API Support
- S3 and AWS Authentication
- Legacy Authentication Scheme for S3 API
- Iceberg
- ICU
- inet
- Lance
- Legacy Parser
- MotherDuck
- MySQL
- ODBC
- Quack
- PostgreSQL
- Sirius
- Spatial
- SQLite
- SQLSmith
- TPC-DS
- TPC-H
- UI
- Unity Catalog
- Vortex
- VSS
- Quack Remote Protocol
- Guides
- Overview
- Data Viewers
- Database Integration
- File Formats
- Overview
- CSV Import
- CSV Export
- Directly Reading Files
- Directly Reading DuckDB Databases
- Excel Import
- Excel Export
- JSON Import
- JSON Export
- Parquet Import
- Parquet Export
- Querying Parquet Files
- File Access with the file: Protocol
- Meta Queries
- Describe Table
- EXPLAIN: Inspect Query Plans
- EXPLAIN ANALYZE: Profile Queries
- List Tables
- Summarize
- DuckDB Environment
- Network and Cloud Storage
- Overview
- HTTP Parquet Import
- HTTP CSV Import
- S3 Parquet Import
- S3 Parquet Export
- S3 Iceberg Import
- S3 Express One
- GCS Import
- Cloudflare R2 Import
- DuckDB over HTTPS / S3
- Share a Views-Only Database
- Fastly Object Storage Import
- SeaweedFS Import
- Tigris Import
- ODBC
- Performance
- Overview
- Environment
- Import
- Schema
- Indexing
- Join Operations
- File Formats
- How to Tune Workloads
- My Workload Is Slow
- Out-of-Memory Issues
- Benchmarks
- Working with Huge Databases
- Python
- Installation
- Executing SQL
- Jupyter Notebooks
- marimo Notebooks
- SQL on Pandas
- Import from Pandas
- Export to Pandas
- Import from Numpy
- Export to Numpy
- SQL on Arrow
- Import from Arrow
- Export to Arrow
- Relational API on Pandas
- Multiple Python Threads
- Integration with Ibis
- Integration with Polars
- Integration with PyTorch
- Using fsspec Filesystems
- SQL Editors
- Beekeeper Studio SQL Editor
- DBeaver SQL IDE
- DBine SQL Editor
- LibreDB Studio SQL Editor
- VisuaLeaf SQL Editor
- SQL Features
- AsOf Join
- Full-Text Search
- Graph Queries
- query and query_table Functions
- Merge Statement for SCD Type 2
- Timestamp Issues
- Snippets
- Creating Synthetic Data
- Dutch Railway Datasets
- Sharing Macros
- Analyzing a Git Repository
- Importing Duckbox Tables
- Copying an In-Memory Database to a File
- Calculating a Database Checksum
- Troubleshooting
- Glossary of Terms
- Browsing Offline
- Operations Manual
- Overview
- Migrating to DuckDB v2.0
- Backup Extension Repositories
- DuckDB's Footprint
- Installing DuckDB
- Logging
- User Agents
- Securing DuckDB
- Non-Deterministic Behavior
- Limits
- DuckDB Docker Container
- Development
- Overview
- DuckDB Repositories
- Release Cycle
- Metrics
- Profiling
- Building DuckDB
- Overview
- Build Configuration
- Building Extensions
- Statically Linking Extensions
- Android
- Linux
- macOS
- Raspberry Pi
- Windows
- Python
- R
- Troubleshooting
- Unofficial and Unsupported Platforms
- Benchmark Suite
- Testing
- Overview
- sqllogictest Introduction
- Writing Tests
- Unit Tester Configuration
- Debugging
- Result Verification
- Persistent Testing
- Loops
- Multiple Connections
- Catch
- Internal Errors
- Internals
- Sitemap
- Live Demo
Installation To use the DuckDB C++ API, download the
libduckdbarchive for your platform.The latest stable version of the DuckDB C++ API is 2.0.0.
Warning DuckDB's C++ API is internal. It is not guaranteed to be stable and can change without notice. If you would like to build an application on DuckDB, we recommend using the C API.
Installation
The DuckDB C++ API can be installed as part of the libduckdb packages. Please see the installation page for details. Starting with DuckDB 2.0, using the C++ API requires a C++17 compiler.
Basic API Usage
DuckDB implements a custom C++ API. This is built around the abstractions of a database instance (DuckDB class), multiple Connections to the database instance and QueryResult instances as the result of queries. The header file for the C++ API is duckdb.hpp.
Startup & Shutdown
To use DuckDB, you must first initialize a DuckDB instance using its constructor. DuckDB() takes as parameter the database file to read and write from. The special value nullptr can be used to create an in-memory database. Note that for an in-memory database no data is persisted to disk (i.e., all data is lost when you exit the process). The second parameter to the DuckDB constructor is an optional DBConfig object. In DBConfig, you can set various database parameters, for example the read/write mode or memory limits. The DuckDB constructor may throw exceptions, for example if the database file is not usable.
With the DuckDB instance, you can create one or many Connection instances using the Connection() constructor. While connections should be thread-safe, they will be locked during querying. It is therefore recommended that each thread uses its own connection if you are in a multithreaded environment.
DuckDB db(nullptr);
Connection con(db);
Querying
Connections expose the Query() method to send a SQL query string to DuckDB from C++. Query() runs the query to completion and returns a QueryResult that retains the result in memory, so it can be read repeatedly. To submit a query without blocking, use Submit().
// create a table
con.Query("CREATE TABLE integers (i INTEGER, j INTEGER)");
// insert three rows into the table
con.Query("INSERT INTO integers VALUES (3, 4), (5, 6), (7, NULL)");
auto result = con.Query("SELECT * FROM integers");
if (result->HasError()) {
cerr << result->GetError() << endl;
} else {
cout << result->ToString() << endl;
}
Query will not throw exceptions under normal circumstances. Instead, invalid queries or other issues cause the HasError() method of the returned QueryResult to return true. In this case, the error message is available via GetError(). The methods GetErrorType() and GetErrorObject() are also available for any QueryResult instance which may aid in more explicit error handling.
auto result = con.Query("INSERT INTO integers VALUES (1, 2)");
if (result->HasError()) {
auto errorType = result->GetErrorType();
switch (errorType) {
case duckdb::ExceptionType::CONSTRAINT: {
// Example handling
auto errorObject = result->GetErrorObject();
errorObject.ConvertErrorToJSON();
std::cout << errorObject.Message() << std::endl;
break;
}
// More handling
}
} else {
// Normal code
}
If successful, other fields are set: the type of statement that was just executed (e.g., StatementType::INSERT_STATEMENT) is returned by GetStatementType(). The high-level (“Logical type”/“SQL type”) types of the result set columns are returned by GetTypes(). The names of the result columns are returned by GetNames() as a vector of strings. In case multiple result sets are returned, for example because the result set contained multiple statements, the result set can be chained using the next field.
Because Query() retains the full result, the result set can be traversed directly by index. Use ColumnCount() and RowCount() for the dimensions, and Collection().GetValue(column, row) to retrieve an individual value as a duckdb::Value:
auto result = con.Query("SELECT * FROM integers");
if (result->HasError()) {
cerr << result->GetError() << endl;
} else {
// Print the column names as a header row
for (idx_t col_idx = 0; col_idx < result->ColumnCount(); col_idx++) {
cout << result->GetNames()[col_idx];
cout << (col_idx + 1 < result->ColumnCount() ? "\t" : "\n");
}
// Iterate over every row and column of the materialized result
for (idx_t row_idx = 0; row_idx < result->RowCount(); row_idx++) {
for (idx_t col_idx = 0; col_idx < result->ColumnCount(); col_idx++) {
// GetValue returns a duckdb::Value; ToString renders it (NULL values become "NULL")
cout << result->Collection().GetValue(col_idx, row_idx).ToString();
cout << (col_idx + 1 < result->ColumnCount() ? "\t" : "\n");
}
}
}
DuckDB also supports prepared statements in the C++ API with the Prepare() method. This returns an instance of PreparedStatement. This instance can be used to execute the prepared statement with parameters. Below is an example:
std::unique_ptr<PreparedStatement> prepare = con.Prepare("SELECT count(*) FROM a WHERE i = $1");
std::unique_ptr<QueryResult> result = prepare->Execute(12);
Warning Do not use prepared statements to insert large amounts of data into DuckDB. See the data import documentation for better options.
UDF API
Deprecated The
ConnectionmethodsCreateScalarFunction(),CreateVectorizedFunction()andCreateAggregateFunction()were removed in DuckDB 2.0. To define user-defined functions, use the scalar function interface of the C API or write an extension.