### Create and configure Connectors Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/connector-and-connections.md Examples showing basic in-memory setup, file-backed initialization, and error handling during connector creation. ```go // Basic connector for in-memory database c, err := duckdb.NewConnector("", func(driver.ExecerContext) error { return nil }) if err != nil { panic(err) } defer c.Close() db := sql.OpenDB(c) defer db.Close() // File-backed database with initialization c, err := duckdb.NewConnector("my.db?threads=4", func(execer driver.ExecerContext) error { _, err := execer.ExecContext(context.Background(), "SET schema='main'", nil) if err != nil { return err } _, err = execer.ExecContext(context.Background(), "CREATE TABLE IF NOT EXISTS users(id INTEGER)", nil) return err }) if err != nil { panic(err) } defer c.Close() // Error handling during initialization c, err := duckdb.NewConnector("test.db", func(execer driver.ExecerContext) error { _, err := execer.ExecContext(context.Background(), "PRAGMA enable_profiling", nil) if err != nil { return fmt.Errorf("failed to enable profiling: %w", err) } return nil }) if err != nil { fmt.Printf("Failed to create connector: %v\n", err) } defer c.Close() ``` -------------------------------- ### Install build-essential on Ubuntu Source: https://github.com/duckdb/duckdb-go/blob/main/README.md Use this command to install necessary build tools if encountering CGO-related build errors. ```bash sudo apt-get update && sudo apt-get install build-essential ``` -------------------------------- ### Manage connections with context Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/connector-and-connections.md Examples demonstrating how to connect using background, timeout, and cancellable contexts. ```go c, err := duckdb.NewConnector("", nil) defer c.Close() ctx := context.Background() conn, err := c.Connect(ctx) if err != nil { panic(err) } defer conn.Close() // With timeout ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() conn, err := c.Connect(ctx) if err != nil { panic(err) } defer conn.Close() // With cancellation propagation ctx, cancel := context.WithCancel(context.Background()) defer cancel() conn, err := c.Connect(ctx) if err != nil { panic(err) } defer conn.Close() cancel() // Cancels operations using this context ``` -------------------------------- ### Create and use an Appender Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/appender-api.md Example demonstrating the full lifecycle of creating an Appender from a database connection. ```go db, err := sql.Open("duckdb", "test.db") if err != nil { panic(err) } defer db.Close() // Create table db.Exec("CREATE TABLE users(id INTEGER, name VARCHAR)") conn, err := db.Conn(context.Background()) if err != nil { panic(err) } defer conn.Close() appender, err := duckdb.NewAppender(conn, "", "main", "users") if err != nil { panic(err) } defer appender.Close() ``` -------------------------------- ### Initialize TypeInfo with DecimalDetails Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/types-and-values.md Example of initializing TypeInfo for a decimal type. ```go info := TypeInfo{ Type: duckdb.TYPE_DECIMAL, Details: &DecimalDetails{ Width: 18, Scale: 2, }, } ``` -------------------------------- ### Example usage of NewStructEntry Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/types-and-values.md Demonstrates creating a struct entry and accessing its name. ```go entry, err := duckdb.NewStructEntry( TypeInfo{Type: duckdb.TYPE_VARCHAR}, "firstName", ) if err != nil { panic(err) } fmt.Printf("Entry name: %s\n", entry.Name()) ``` -------------------------------- ### Connect to DuckDB in Go Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/README.md Examples for establishing connections to DuckDB databases using the database/sql interface. ```go import ( "database/sql" _ "github.com/duckdb/duckdb-go/v2" ) // In-memory database db, err := sql.Open("duckdb", "") defer db.Close() // Query rows, err := db.QueryContext(ctx, "SELECT 42", nil) ``` ```go db, err := sql.Open("duckdb", "/path/to/database.db") defer db.Close() ``` ```go db, err := sql.Open("duckdb", "/path/to/db.db?threads=4&access_mode=read_only") defer db.Close() ``` -------------------------------- ### Configure Scalar UDFs Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/user-defined-functions.md Examples of configuring scalar UDFs for simple, variadic, and null-handling scenarios. ```go // Simple scalar function: INTEGER x INTEGER -> VARCHAR config := duckdb.ScalarFuncConfig{ InputTypeInfos: []duckdb.TypeInfo{ {Type: duckdb.TYPE_INTEGER}, {Type: duckdb.TYPE_INTEGER}, }, ResultTypeInfo: duckdb.TypeInfo{Type: duckdb.TYPE_VARCHAR}, Volatile: false, } // Variadic function: accepts any number of INTEGER parameters config := duckdb.ScalarFuncConfig{ InputTypeInfos: []duckdb.TypeInfo{}, ResultTypeInfo: duckdb.TypeInfo{Type: duckdb.TYPE_INTEGER}, VariadicTypeInfo: duckdb.TypeInfo{Type: duckdb.TYPE_INTEGER}, } // Function with special NULL handling config := duckdb.ScalarFuncConfig{ InputTypeInfos: []duckdb.TypeInfo{ {Type: duckdb.TYPE_VARCHAR}, }, ResultTypeInfo: duckdb.TypeInfo{Type: duckdb.TYPE_VARCHAR}, SpecialNullHandling: true, // Explicitly handle NULLs } ``` -------------------------------- ### Initialize Connections with Callbacks Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/configuration.md Use NewConnector with a callback function to execute setup queries like schema configuration or extension loading upon connection creation. ```go c, err := duckdb.NewConnector("/path/to/foo.db?threads=4", func(execer driver.ExecerContext) error { // Execute initialization queries bootQueries := []string{ "SET schema=main", "SET search_path=main", "INSTALL json", "LOAD json", } for _, query := range bootQueries { _, err := execer.ExecContext(context.Background(), query, nil) if err != nil { return err } } return nil }) if err != nil { panic(err) } defer c.Close() db := sql.OpenDB(c) defer db.Close() ``` -------------------------------- ### Install DuckDB-Go Source: https://github.com/duckdb/duckdb-go/blob/main/README.md Use this command to add the DuckDB-Go v2 package to your Go project. ```sh go get github.com/duckdb/duckdb-go/v2 ``` -------------------------------- ### Bulk Insert with Appender Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/appender-api.md A complete example demonstrating how to open a connection, initialize an appender, perform bulk inserts, and flush the data to the database. ```go package main import ( "context" "database/sql" "fmt" "log" "github.com/duckdb/duckdb-go/v2" ) func main() { // Open database db, err := sql.Open("duckdb", "bulk_insert.db") if err != nil { log.Fatal(err) } defer db.Close() // Create table _, err = db.Exec("CREATE TABLE IF NOT EXISTS products(id INTEGER, name VARCHAR, price DOUBLE)") if err != nil { log.Fatal(err) } // Get connection conn, err := db.Conn(context.Background()) if err != nil { log.Fatal(err) } defer conn.Close() // Create appender appender, err := duckdb.NewAppenderFromConn(conn, "main", "products") if err != nil { log.Fatal(err) } defer func() { if err := appender.Close(); err != nil { log.Printf("Failed to close appender: %v\n", err) } }() // Append 10,000 rows for i := 1; i <= 10000; i++ { if err := appender.AppendRow( int32(i), fmt.Sprintf("Product%d", i), 99.99 + float64(i % 100), ); err != nil { appender.Clear() log.Fatalf("Failed to append row %d: %v", i, err) } } // Flush to database if err := appender.Flush(); err != nil { log.Fatal(err) } fmt.Println("Successfully inserted 10,000 rows") } ``` -------------------------------- ### Create Appender from connection Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/appender-api.md Example of creating an Appender using the convenience function for the default catalog. ```go appender, err := duckdb.NewAppenderFromConn(conn, "public", "users") if err != nil { panic(err) } defer appender.Close() ``` -------------------------------- ### Handling Configuration Errors Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/configuration.md Examples of invalid DSN options and the correct syntax for setting configuration parameters. ```go db, err := sql.Open("duckdb", "/invalid/path/db.db?threads=abc") if err != nil { // Would fail with "could not set invalid or local option: threads=abc" panic(err) } // Use valid integer for threads db, err := sql.Open("duckdb", "/path/to/db.db?threads=4") if err != nil { panic(err) } ``` -------------------------------- ### Install GCC on Windows via msys64 Source: https://github.com/duckdb/duckdb-go/blob/main/README.md Install the required GCC compiler for Windows using the pacman package manager within an msys64 shell. ```sh pacman -S mingw-w64-ucrt-x86_64-gcc ``` -------------------------------- ### Execute a Transaction with Conn.BeginTx Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/connector-and-connections.md Demonstrates starting a transaction, executing an insert, and committing the changes. Note that read-only transactions and custom isolation levels are not supported. ```go conn, err := db.Conn(context.Background()) defer conn.Close() tx, err := conn.BeginTx(context.Background(), &sql.TxOptions{}) if err != nil { panic(err) } defer tx.Rollback() if err := tx.ExecContext(context.Background(), "INSERT INTO users(id, name) VALUES(?, ?)", []driver.NamedValue{{Value: int32(1)}, {Value: "Alice"}}); err != nil { return err } // Commit after operations if err := tx.Commit(); err != nil { panic(err) } ``` -------------------------------- ### Get the driver Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/connector-and-connections.md The method signature for retrieving the underlying driver. ```go func (c *Connector) Driver() driver.Driver ``` -------------------------------- ### Configure DuckDB options via DSN Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/configuration.md Examples of passing multiple configuration options, memory limits, and schema settings through the DSN string. ```go // Multiple options dsn := "/path/to/db.db?threads=4&access_mode=read_only&schema=main" db, err := sql.Open("duckdb", dsn) // Memory limit dsn := "?memory_limit=2GB" db, err := sql.Open("duckdb", dsn) // Schema configuration dsn := ":memory:?search_path=schema1,schema2,public" db, err := sql.Open("duckdb", dsn) ``` -------------------------------- ### Implement log callback Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/extensions-and-advanced.md Example implementation of a logging callback function that prints log details to standard output. ```go logCallback := func(level, logType, logMsg string) { fmt.Printf("[%s] [%s] %s\n", level, logType, logMsg) } ``` -------------------------------- ### Open DuckDB connections Source: https://github.com/duckdb/duckdb-go/blob/main/README.md Examples for opening in-memory and persistent database connections using the standard sql.Open function. ```go db, err := sql.Open("duckdb", "") defer db.Close() ``` ```go db, err := sql.Open("duckdb", "/path/to/foo.db") defer db.Close() ``` -------------------------------- ### Open DuckDB connections with DSN Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/configuration.md Examples of connecting to in-memory and file-backed databases using various DSN configurations. ```go // In-memory database db, err := sql.Open("duckdb", "") // File-backed database db, err := sql.Open("duckdb", "/path/to/my.db") // With :memory: prefix (equivalent to empty string) db, err := sql.Open("duckdb", ":memory:") // File with configuration options db, err := sql.Open("duckdb", "/path/to/my.db?threads=4&access_mode=read_only") // In-memory with configuration db, err := sql.Open("duckdb", "?threads=8") ``` -------------------------------- ### Implement Executor Functions Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/user-defined-functions.md Examples of implementing various executor functions for scalar UDFs. ```go // Simple row executor executor := duckdb.RowExecutorFn(func(values []driver.Value) (any, error) { a := values[0].(int32) b := values[1].(int32) return a + b, nil }) // Context-aware executor executor := duckdb.RowContextExecutorFn(func(ctx context.Context, values []driver.Value) (any, error) { select { case <-ctx.Done(): return nil, ctx.Err() default: } return values[0].(string) + values[1].(string), nil }) // Chunk executor for vectorized processing executor := duckdb.ChunkContextExecutorFn(func(ctx context.Context, chunk *duckdb.ChunkIteratorState) error { input := chunk.GetListChild(0) for input.Next() { // Process each value in the chunk } return nil }) // Binder for initialization binder := duckdb.ScalarBinderFn(func(parentCtx context.Context, args []duckdb.ScalarUDFArg) (context.Context, error) { // Check if arguments are foldable and use their values for setup fmt.Printf("Arguments: %v\n", args) return parentCtx, nil }) ``` -------------------------------- ### duckdb.NewConnector Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/duckdb-go-technical-reference.md Creates a new connector with an optional initialization callback for executing setup queries. ```APIDOC ## duckdb.NewConnector(dsn, initFunc) ### Description Creates a connector that allows for custom initialization logic to be executed upon connection creation. ### Parameters - **dsn** (string) - Required - Connection string. - **initFunc** (func) - Required - A function that takes a driver.ExecerContext and returns an error, used for initial setup like setting schemas. ### Example ```go c, err := duckdb.NewConnector("/path/to/foo.db", func(execer driver.ExecerContext) error { _, err := execer.ExecContext(context.Background(), "SET schema=main", nil) return err }) db := sql.OpenDB(c) ``` ``` -------------------------------- ### Register and execute a scalar UDF Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/user-defined-functions.md Provides a complete example of defining a function, registering it with a SQL connection, and executing it via a query. ```go type DoubleFunc struct{} func (f *DoubleFunc) Config() duckdb.ScalarFuncConfig { return duckdb.ScalarFuncConfig{ InputTypeInfos: []duckdb.TypeInfo{{Type: duckdb.TYPE_INTEGER}}, ResultTypeInfo: duckdb.TypeInfo{Type: duckdb.TYPE_INTEGER}, } } func (f *DoubleFunc) Executor() duckdb.ScalarFuncExecutor { return duckdb.ScalarFuncExecutor{ RowExecutor: func(values []driver.Value) (any, error) { return values[0].(int32) * 2, nil }, } } conn, err := db.Conn(context.Background()) if err != nil { panic(err) } defer conn.Close() if err := duckdb.RegisterScalarUDF(conn, "double", &DoubleFunc{}); err != nil { panic(err) } // Use the function rows, err := conn.QueryContext(context.Background(), "SELECT double(5)", nil) if err != nil { panic(err) } defer rows.Close() var result int32 rows.Scan(&result) fmt.Printf("Result: %d\n", result) // Output: 10 ``` -------------------------------- ### Register and use a Table UDF Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/user-defined-functions.md Registration function signature and an example of registering and querying a custom table UDF. ```go func RegisterTableUDF(c *sql.Conn, name string, f TableUDFFunc) error ``` ```go conn, err := db.Conn(context.Background()) if err != nil { panic(err) } defer conn.Close() if err := duckdb.RegisterTableUDF(conn, "my_series", &GenerateSeriesFunc{}); err != nil { panic(err) } // Use the function rows, err := conn.QueryContext(context.Background(), "SELECT * FROM my_series(1, 10)", nil) if err != nil { panic(err) } defer rows.Close() ``` -------------------------------- ### Create and use column-restricted Appender Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/appender-api.md Example of creating an Appender for specific columns and appending a row. ```go // Append only to specific columns; other columns get DEFAULT values appender, err := duckdb.NewAppenderWithColumns(conn, "", "main", "users", []string{"id", "name"}) if err != nil { panic(err) } defer appender.Close() err = appender.AppendRow(int32(1), "Alice") if err != nil { panic(err) } ``` -------------------------------- ### Implement TableUDFFunc interface Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/user-defined-functions.md Interface definition and a concrete implementation example for a table UDF. ```go type TableUDFFunc interface { Config() TableUDFConfig Func(ctx context.Context, input *TableUDFInput) (*TableUDFOutput, error) } ``` ```go type GenerateSeriesFunc struct{} func (f *GenerateSeriesFunc) Config() duckdb.TableUDFConfig { return duckdb.TableUDFConfig{ InputTypeInfos: []duckdb.TypeInfo{ {Type: duckdb.TYPE_INTEGER}, {Type: duckdb.TYPE_INTEGER}, }, ResultTypeInfos: []duckdb.TypeInfo{ {Type: duckdb.TYPE_INTEGER}, }, } } func (f *GenerateSeriesFunc) Func(ctx context.Context, input *duckdb.TableUDFInput) (*duckdb.TableUDFOutput, error) { start := input.GetValue(0, 0).(int32) end := input.GetValue(0, 1).(int32) output := &duckdb.TableUDFOutput{} for i := start; i <= end; i++ { output.Append(i) } return output, nil } ``` -------------------------------- ### Close connector usage Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/connector-and-connections.md Examples showing how to close a connector to ensure data is flushed to disk, noting that the operation is idempotent. ```go c, err := duckdb.NewConnector("persistent.db", nil) if err != nil { panic(err) } // Always close to flush WAL to disk if err := c.Close(); err != nil { log.Fatalf("Failed to close connector: %v", err) } // Idempotent c.Close() // Safe to call again c.Close() // Safe to call again ``` -------------------------------- ### Get Number of Parameters Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/prepared-statements.md Returns the count of placeholders in the prepared statement. Panics if called after the statement is closed. ```go stmt, err := conn.PrepareContext(ctx, "SELECT * FROM users WHERE id = ? AND name = ? AND age > ?") if err != nil { panic(err) } defer stmt.Close() numParams := stmt.NumInput() fmt.Printf("Statement has %d parameters\n", numParams) // Output: 3 ``` -------------------------------- ### Handle Appender Creation Errors in Go Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/errors.md Examples of scenarios triggering appender creation errors, such as missing tables, unsupported column types, or empty column lists. ```go // Table doesn't exist appender, err := duckdb.NewAppenderFromConn(conn, "", "nonexistent_table") // err is errAppenderCreation: table not found // Table with unsupported column type (e.g., VARIANT) appender, err := duckdb.NewAppenderFromConn(conn, "", "table_with_variant") // err is errAppenderCreation: unsupported data type // Empty column list appender, err := duckdb.NewAppenderWithColumns(conn, "", "", "table", []string{}) // err: invalid input, expected non-empty array ``` -------------------------------- ### Conn.BeginTx Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/connector-and-connections.md Starts a new transaction on the DuckDB connection. Note that nested transactions are not supported and only the default isolation level is allowed. ```APIDOC ## Conn.BeginTx ### Description Starts a new transaction on the connection. Only one transaction per connection is supported. ### Signature `func (conn *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error)` ### Parameters - **ctx** (context.Context) - Required - Context for the transaction - **opts** (driver.TxOptions) - Required - Transaction options (ReadOnly not supported, isolation level must be default) ### Returns - **driver.Tx** - Transaction object with Commit() and Rollback() methods - **error** - Transaction error ### Errors - `errBeginTx`: Multiple transactions, read-only mode, or unsupported isolation level - `errClosedCon`: Connection is closed - `errMultipleTx`: Nested transactions not supported - `errReadOnlyTxNotSupported`: ReadOnly transactions not supported - `errIsolationLevelNotSupported`: Only default isolation level supported ``` -------------------------------- ### Initialize database with sql.OpenDB Source: https://github.com/duckdb/duckdb-go/blob/main/README.md Use a custom connector to execute initialization queries before the database is fully opened. ```go c, err := duckdb.NewConnector("/path/to/foo.db?access_mode=read_only&threads=4", func(execer driver.ExecerContext) error { bootQueries := []string{ `SET schema=main`, `SET search_path=main`, } for _, query := range bootQueries { _, err = execer.ExecContext(context.Background(), query, nil) if err != nil { return err } } return nil }) defer c.Close() db := sql.OpenDB(c) defer db.Close() ``` -------------------------------- ### Initialize connection with callbacks Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/duckdb-go-technical-reference.md Use a connector to execute initialization commands like setting schemas before the database is fully opened. ```go c, err := duckdb.NewConnector("/path/to/foo.db?access_mode=read_only&threads=4", func(execer driver.ExecerContext) error { _, err := execer.ExecContext(context.Background(), "SET schema=main", nil) return err }) defer c.Close() db := sql.OpenDB(c) defer db.Close() ``` -------------------------------- ### Using Prepared Statements Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/rows-and-scanning.md Prepare a statement once and execute it multiple times with different parameters to improve performance and security. ```go stmt, err := conn.PrepareContext(context.Background(), "SELECT * FROM users WHERE status = ?") if err != nil { panic(err) } defer stmt.Close() // Reuse statement with different parameters statuses := []string{"active", "pending", "inactive"} for _, status := range statuses { rows, err := stmt.QueryContext(context.Background(), []driver.NamedValue{{Value: status}}) if err != nil { panic(err) } count := 0 for rows.Next() { count++ } rows.Close() fmt.Printf("Status '%s': %d users\n", status, count) } ``` -------------------------------- ### Get Statement Type Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/prepared-statements.md Determines the type of the prepared statement (e.g., SELECT, INSERT). ```go stmt, err := conn.PrepareContext(ctx, "INSERT INTO users(id, name) VALUES(?, ?)") if err != nil { panic(err) } defer stmt.Close() stmtType, err := stmt.StatementType() if err != nil { panic(err) } if stmtType == duckdb.STATEMENT_TYPE_INSERT { fmt.Println("This is an INSERT statement") } ``` -------------------------------- ### Get Parameter Type Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/prepared-statements.md Returns the DuckDB type of a parameter at the specified 1-based index. ```go stmt, err := conn.PrepareContext(ctx, "SELECT * FROM users WHERE id = ? AND active = ?") if err != nil { panic(err) } defer stmt.Close() paramType, err := stmt.ParamType(1) if err != nil { panic(err) } fmt.Printf("First parameter type: %v\n", paramType) ``` -------------------------------- ### Connect to the database Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/connector-and-connections.md The method signature for establishing a connection using a context. ```go func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) ``` -------------------------------- ### Initialize Arrow interface Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/extensions-and-advanced.md Create an Arrow interface wrapper from an existing driver connection. ```go func NewArrowFromConn(driverConn driver.Conn) (*Arrow, error) ``` ```go c, err := duckdb.NewConnector("", nil) if err != nil { panic(err) } defer c.Close() conn, err := c.Connect(context.Background()) if err != nil { panic(err) } defer conn.Close() arrow, err := duckdb.NewArrowFromConn(conn) if err != nil { panic(err) } ``` -------------------------------- ### Handle Connection Initialization Errors Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/errors.md Demonstrates catching errors when a database file is inaccessible or initialization fails during connector creation. ```go c, err := duckdb.NewConnector("/nonexistent/path/db.db", nil) if err != nil { // "could not connect to database: ..." fmt.Println(err) } ``` -------------------------------- ### Get Parameter Name Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/prepared-statements.md Retrieves the name of a parameter by its 1-based index. Returns an error if the index is out of range. ```go stmt, err := conn.PrepareContext(ctx, "SELECT * FROM users WHERE id = $1 AND name = $2") if err != nil { panic(err) } defer stmt.Close() for i := 1; i <= stmt.NumInput(); i++ { name, err := stmt.ParamName(i) if err != nil { panic(err) } fmt.Printf("Param %d: %s\n", i, name) } ``` -------------------------------- ### Register and activate custom logger Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/extensions-and-advanced.md Complete workflow for creating a connector, registering a custom logger, and activating it via SQL execution. ```go c, err := duckdb.NewConnector("", nil) if err != nil { panic(err) } defer c.Close() // Register custom logging callbacks := duckdb.LoggerCallbacks{ DefaultLoggerCallback: func(level, logType, logMsg string) { fmt.Printf("[%s] [%s] %s\n", level, logType, logMsg) }, } if err := duckdb.RegisterLogStorage(c, "custom_logger", callbacks); err != nil { panic(err) } db := sql.OpenDB(c) defer db.Close() // Activate the custom logger _, err = db.Exec("SET logging_storage = 'custom_logger'") if err != nil { panic(err) } ``` -------------------------------- ### Initialize a new Connector Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/connector-and-connections.md The function signature for creating a new connector instance. ```go func NewConnector(dsn string, connInitFn func(execer driver.ExecerContext) error) (*Connector, error) ``` -------------------------------- ### Bind query parameters with TypedValue Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/types-and-values.md Example of using duckdb.Typed to force TIMESTAMP_NS binding for query parameters. ```go import ( "time" "github.com/duckdb/duckdb-go/v2" ) start := time.Date(2024, time.April, 5, 0, 0, 0, 0, time.UTC) // Force TIMESTAMP_NS binding result, err := conn.QueryContext(ctx, "SELECT COUNT(*) FROM events WHERE ts >= ? AND ts < ?", []driver.NamedValue{ {Value: duckdb.Typed(start, duckdb.TYPE_TIMESTAMP_NS)}, {Value: duckdb.Typed(start.AddDate(0, 0, 1), duckdb.TYPE_TIMESTAMP_NS)}, }) if err != nil { panic(err) } defer result.Close() ``` -------------------------------- ### Begin and Commit a Transaction in Go Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/extensions-and-advanced.md Initiates a transaction using BeginTx, executes statements, and commits the changes. Ensure proper error handling and rollback in case of failure. ```go conn, err := db.Conn(context.Background()) if err != nil { panic(err) } defer conn.Close() tx, err := conn.BeginTx(context.Background(), &sql.TxOptions{}) if err != nil { panic(err) } // Execute statements within transaction _, err = tx.ExecContext(context.Background(), "INSERT INTO users(id, name) VALUES(?, ?)", []driver.NamedValue{{Value: 1}, {Value: "Alice"}}) if err != nil { tx.Rollback() panic(err) } // Commit or rollback if err := tx.Commit(); err != nil { panic(err) } ``` -------------------------------- ### Configure DuckDB with DSN parameters Source: https://github.com/duckdb/duckdb-go/blob/main/README.md Pass configuration options as query-style parameters in the DSN string. ```go db, err := sql.Open("duckdb", "/path/to/foo.db?access_mode=read_only&threads=4") defer db.Close() ``` -------------------------------- ### Manage Query Contexts Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/extensions-and-advanced.md Demonstrates using context with timeouts and manual cancellation for queries via the standard database/sql interface. ```go db, err := sql.Open("duckdb", "") if err != nil { panic(err) } defer db.Close() // Context with timeout ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() rows, err := db.QueryContext(ctx, "SELECT * FROM large_table", nil) if err != nil { if errors.Is(err, context.DeadlineExceeded) { fmt.Println("Query timed out") } panic(err) } defer rows.Close() // Context with cancellation ctx, cancel := context.WithCancel(context.Background()) go func() { time.Sleep(2 * time.Second) cancel() // Cancel query after 2 seconds }() rows, err := db.QueryContext(ctx, "SELECT * FROM huge_table", nil) if err != nil { if errors.Is(err, context.Canceled) { fmt.Println("Query was cancelled") } panic(err) } defer rows.Close() ``` -------------------------------- ### Handle Unsupported Type Errors in Go Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/errors.md Example of an error triggered when attempting to use an appender with a table containing an unsupported DuckDB type. ```go // VARIANT type not supported in appender appender, err := duckdb.NewAppenderFromConn(conn, "", "table_with_variant") // err contains "unsupported data type: variant" ``` -------------------------------- ### Retrieve and use profiling information Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/extensions-and-advanced.md Demonstrates enabling profiling, executing a query, and retrieving the resulting metrics via GetProfilingInfo. ```go db, err := sql.Open("duckdb", "") if err != nil { panic(err) } defer db.Close() conn, err := db.Conn(context.Background()) if err != nil { panic(err) } defer conn.Close() // Enable profiling _, err = conn.ExecContext(context.Background(), "PRAGMA enable_profiling = 'no_output'", nil) if err != nil { panic(err) } _, err = conn.ExecContext(context.Background(), "PRAGMA profiling_mode = 'detailed'", nil) if err != nil { panic(err) } // Execute a query rows, err := conn.QueryContext(context.Background(), "SELECT * FROM generate_series(1, 1000)", nil) if err != nil { panic(err) } defer rows.Close() // Drain rows for rows.Next() { var val int32 rows.Scan(&val) } // Get profiling info info, err := duckdb.GetProfilingInfo(conn) if err != nil { panic(err) } // Print metrics for k, v := range info.Metrics { fmt.Printf("%s: %s\n", k, v) } _, err = conn.ExecContext(context.Background(), "PRAGMA disable_profiling", nil) if err != nil { panic(err) } ``` -------------------------------- ### Build the DuckDB Go driver Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/README.md Use these commands to compile the driver with specific build configurations. ```bash go build ``` ```bash CGO_ENABLED=1 CGO_LDFLAGS="-lduckdb -L/path/to/libs" go build -tags=duckdb_use_lib ``` ```bash go build -tags="duckdb_arrow" ``` ```bash CGO_ENABLED=1 CPPFLAGS="-DDUCKDB_STATIC_BUILD" CGO_LDFLAGS="-lduckdb_bundle -lc++ -L/path/to/libs" go build -tags=duckdb_use_static_lib ``` -------------------------------- ### Handle Cast Errors in Go Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/errors.md Example of a type mismatch error occurring during row scanning when the database type cannot be cast to the Go variable type. ```go var stringVal string // Cannot scan INTEGER into string (would need BIT -> string conversion) err := rows.Scan(&stringVal) // Type mismatch error ``` -------------------------------- ### Execute PRAGMA configuration statements Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/configuration.md Apply runtime configuration settings by executing PRAGMA statements via a database connection. ```go db, err := sql.Open("duckdb", "") if err != nil { panic(err) } defer db.Close() conn, err := db.Conn(context.Background()) if err != nil { panic(err) } defer conn.Close() // Enable profiling _, err = conn.ExecContext(context.Background(), "PRAGMA enable_profiling = 'no_output'", nil) if err != nil { panic(err) } // Set profiling mode _, err = conn.ExecContext(context.Background(), "PRAGMA profiling_mode = 'detailed'", nil) if err != nil { panic(err) } // Disable profiling _, err = conn.ExecContext(context.Background(), "PRAGMA disable_profiling", nil) if err != nil { panic(err) } ``` -------------------------------- ### Initialize NewAppenderFromConn Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/appender-api.md Function signature for creating an Appender using the default catalog. ```go func NewAppenderFromConn(driverConn driver.Conn, schema, table string) (*Appender, error) ``` -------------------------------- ### sql.Open Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/duckdb-go-technical-reference.md Establishes a connection to a DuckDB database using the standard database/sql interface. ```APIDOC ## sql.Open("duckdb", dsn) ### Description Opens a new database connection. The DSN can be an empty string for an in-memory database, a file path for a persistent database, or a path with query parameters for configuration. ### Parameters - **driverName** (string) - Required - Must be "duckdb". - **dsn** (string) - Required - Connection string (e.g., "", "/path/to/db.db", or "/path/to/db.db?access_mode=read_only"). ### Example ```go db, err := sql.Open("duckdb", "/path/to/database.db?access_mode=read_only&threads=4") ``` ``` -------------------------------- ### Initialize NewAppender Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/appender-api.md Function signature for creating a new Appender instance. ```go func NewAppender(driverConn driver.Conn, catalog, schema, table string) (*Appender, error) ``` -------------------------------- ### Import the main package Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/duckdb-go-technical-reference.md Access exported symbols by importing the main driver package. ```go import "github.com/duckdb/duckdb-go/v2" ``` -------------------------------- ### Manage DuckDB resources with Close() Source: https://github.com/duckdb/duckdb-go/blob/main/README.md Demonstrates proper resource cleanup for database connections, queries, appenders, and connectors to ensure memory is freed and data is synchronized. ```go db, err := sql.Open("duckdb", "") defer db.Close() conn, err := db.Conn(context.Background()) defer conn.Close() rows, err := conn.QueryContext(context.Background(), "SELECT 42") // Alternatively, rows.Next() has to return false. rows.Close() appender, err := duckdb.NewAppenderFromConn(conn, "", "test") defer appender.Close() c, err := duckdb.NewConnector("", nil) // Optional, if passed to sql.OpenDB. defer c.Close() ``` -------------------------------- ### Handle Prepare Query Errors Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/errors.md Illustrates catching syntax errors during the query preparation phase. ```go stmt, err := conn.Prepare("INVALID QUERY SYNTAX") if err != nil { // "could not prepare query: ..." fmt.Println(err) } ``` -------------------------------- ### Define ScalarFuncExecutor implementations Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/user-defined-functions.md Demonstrates various ways to initialize a ScalarFuncExecutor using row-based, context-aware, or binder-based execution patterns. ```go // Row-based execution executor := duckdb.ScalarFuncExecutor{ RowExecutor: func(values []driver.Value) (any, error) { return values[0].(int32) * 2, nil }, } // Context-aware execution executor := duckdb.ScalarFuncExecutor{ RowContextExecutor: func(ctx context.Context, values []driver.Value) (any, error) { select { case <-ctx.Done(): return nil, ctx.Err() default: } return values[0].(int32) + 1, nil }, } // With binder for setup executor := duckdb.ScalarFuncExecutor{ ScalarBinder: func(parentCtx context.Context, args []duckdb.ScalarUDFArg) (context.Context, error) { return parentCtx, nil }, RowContextExecutor: func(ctx context.Context, values []driver.Value) (any, error) { return values[0].(string), nil }, } ``` -------------------------------- ### CLion Build Configuration: build-go-debug Source: https://github.com/duckdb/duckdb-go/blob/main/docs/debugging/debugging-duckdb-src.MD Import this XML configuration into CLion to create a 'build-go-debug' run configuration. It points to the `go-build-duckdb-debug.sh` script and sets its arguments. ```xml ``` -------------------------------- ### Use the DuckDB Appender API Source: https://github.com/duckdb/duckdb-go/blob/main/README.md Shows how to initialize a connector, establish a connection, and use an Appender to insert rows into a specific table. ```go c, err := duckdb.NewConnector("test.db", nil) defer c.Close() conn, err := c.Connect(context.Background()) defer conn.Close() // Obtain an appender from the connection. // NOTE: The table 'test_tbl' must exist in test.db. appender, err := NewAppenderFromConn(conn, "", "test_tbl") defer appender.Close() err = appender.AppendRow(...) ``` -------------------------------- ### Build module with custom static library Source: https://github.com/duckdb/duckdb-go/blob/main/README.md Use this command to build your Go module against a custom static DuckDB library on Darwin ARM64. ```sh CGO_ENABLED=1 CPPFLAGS="-DDUCKDB_STATIC_BUILD" CGO_LDFLAGS="-lduckdb_bundle -lc++ -L/path/to/libs" go build -tags=duckdb_use_static_lib ``` -------------------------------- ### Build Go App with DuckDB Debug Library Source: https://github.com/duckdb/duckdb-go/blob/main/docs/debugging/debugging-duckdb-src.MD Use this script to build your Go application, linking it against the locally built DuckDB debug library. It sets necessary CGO flags and invokes `go build` with debug options. ```bash scripts/go-build-duckdb-debug.sh /absolute/path/to/your/go/app [package_or_dir] [output_name] ``` ```bash # Build a debug build from the DuckDB repo root: make debug # Build the Go application, linking to this DuckDB repo's debug library (`libduckdb`) scripts/go-build-duckdb-debug.sh ~/Development/example-duckdb-go-project ./examples/simple simple_debug ``` -------------------------------- ### Configure static library linking Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/configuration.md Use custom static libraries during the build process by setting CGO flags and the duckdb_use_static_lib tag. ```bash # Use custom static library CGO_ENABLED=1 CPPFLAGS="-DDUCKDB_STATIC_BUILD" \ CGO_LDFLAGS="-lduckdb_bundle -lc++ -L/path/to/libs" \ go build -tags=duckdb_use_static_lib ``` -------------------------------- ### Append single and multiple rows with Appender.AppendRow Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/appender-api.md Demonstrates initializing an appender and using AppendRow to insert data either individually or within a loop. ```go appender, err := duckdb.NewAppenderFromConn(conn, "", "users") if err != nil { panic(err) } defer appender.Close() // Append a single row if err := appender.AppendRow(int32(1), "Alice", 30); err != nil { panic(err) } // Append multiple rows in a loop for i := 1; i <= 1000; i++ { if err := appender.AppendRow(int32(i), fmt.Sprintf("User%d", i)); err != nil { // Handle error — appender may be invalidated appender.Clear() // Clear buffered data break } } // Flush or Close to finalize if err := appender.Flush(); err != nil { panic(err) } ``` -------------------------------- ### Bind Parameters Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/prepared-statements.md Binds values to the prepared statement placeholders. ```go stmt, err := conn.PrepareContext(ctx, "SELECT * FROM users WHERE id = ?") if err != nil { panic(err) } defer stmt.Close() err = stmt.Bind([]driver.NamedValue{{Value: int32(42)}}) if err != nil { panic(err) } ``` -------------------------------- ### Handle Configuration Errors in DuckDB-Go Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/errors.md Demonstrates catching errors when providing invalid configuration options to the connector. ```go c, err := duckdb.NewConnector("?threads=invalid", nil) if err != nil { // "could not set invalid or local option: threads=invalid" fmt.Println(err) } ``` -------------------------------- ### Connector.Connect Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/connector-and-connections.md Establishes a new database connection using the provided context. ```APIDOC ## Connector.Connect ### Description Creates a new database connection using the connector's configuration. The context allows for cancellation and timeout propagation. ### Signature `func (c *Connector) Connect(ctx context.Context) (driver.Conn, error)` ### Parameters - **ctx** (context.Context) - Required - Context for the connection, used to propagate cancellation signals. ### Returns - **driver.Conn** (driver.Conn) - A new database connection ready for queries. - **error** (error) - Connection or initialization error. ``` -------------------------------- ### Context Management Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/extensions-and-advanced.md The driver supports query cancellation and timeouts through standard Go context management using the database/sql interface. ```APIDOC ## Context Management ### Description The driver maintains a thread-safe context store per connection for handling query cancellation and timeouts. Contexts are automatically managed through the standard `database/sql` interface. ### Supported Methods - `QueryContext()` - `ExecContext()` - `PrepareContext()` - `BeginTx()` ### Example ```go ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() rows, err := db.QueryContext(ctx, "SELECT * FROM large_table", nil) ``` ``` -------------------------------- ### Enable and Retrieve DuckDB Profiling Information Source: https://github.com/duckdb/duckdb-go/blob/main/README.md Configures a connection for profiling, executes a query, and retrieves the resulting profiling metrics. ```Go db, err := sql.Open("duckdb", "") defer db.Close() conn, err := db.Conn(context.Background()) defer conn.Close() _, err = conn.ExecContext(context.Background(), `PRAGMA enable_profiling = 'no_output'`) _, err = conn.ExecContext(context.Background(), `PRAGMA profiling_mode = 'detailed'`) res, err := conn.QueryContext(context.Background(), `SELECT 42`) defer res.Close() info, err := GetProfilingInfo(conn) _, err = conn.ExecContext(context.Background(), `PRAGMA disable_profiling`) ``` -------------------------------- ### Query with Arrow Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/extensions-and-advanced.md Execute a query and retrieve results as an Apache Arrow record reader. ```go func (a *Arrow) QueryContext(ctx context.Context, query string, args ...any) (array.RecordReader, error) ``` ```go arrow, err := duckdb.NewArrowFromConn(conn) if err != nil { panic(err) } reader, err := arrow.QueryContext(context.Background(), "SELECT * FROM generate_series(1, 10)") if err != nil { panic(err) } defer reader.Release() for reader.Next() { record := reader.Record() // Process Apache Arrow record for i := int64(0); i < record.NumRows(); i++ { // Access record data } } if err := reader.Err(); err != nil { panic(err) } ``` -------------------------------- ### Distinguish Configuration Errors Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/errors.md Inspect error strings to differentiate between invalid configuration options and DSN syntax errors. ```go c, err := duckdb.NewConnector("invalid.db?bad_option=123", nil) if err != nil { if strings.Contains(err.Error(), "set invalid or local option") { fmt.Println("Configuration option is invalid") } else if strings.Contains(err.Error(), "parse DSN") { fmt.Println("DSN syntax is invalid") } } ``` -------------------------------- ### Preparing Statements with Conn.Prepare in Go Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/connector-and-connections.md Prepares a SQL statement for execution. Note that multi-statement queries without context may trigger errors. ```go func (conn *Conn) Prepare(query string) (driver.Stmt, error) ``` ```go conn, err := db.Conn(context.Background()) defer conn.Close() stmt, err := conn.Prepare("SELECT * FROM users WHERE id = ?") if err != nil { panic(err) } defer stmt.Close() ``` -------------------------------- ### Configure Connection Pool Settings Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/configuration.md Adjust pool parameters like max open connections, idle connections, and connection lifetimes using the standard database/sql interface. ```go db, err := sql.Open("duckdb", "") if err != nil { panic(err) } defer db.Close() // Maximum number of open connections db.SetMaxOpenConns(25) // Maximum number of idle connections db.SetMaxIdleConns(5) // Maximum lifetime of a connection db.SetConnMaxLifetime(time.Hour) // Maximum idle time before closing db.SetConnMaxIdleTime(10 * time.Minute) ``` -------------------------------- ### Executing with Stmt.Exec Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/prepared-statements.md Executes a prepared statement such as an INSERT, returning the result of the operation. ```go stmt, err := conn.PrepareContext(ctx, "INSERT INTO users(id, name) VALUES(?, ?)") if err != nil { panic(err) } defer stmt.Close() result, err := stmt.Exec([]driver.NamedValue{ {Value: int32(1)}, {Value: "Alice"}, }) if err != nil { panic(err) } rows, err := result.RowsAffected() fmt.Printf("Inserted %d rows\n", rows) ``` -------------------------------- ### Execute Query Source: https://github.com/duckdb/duckdb-go/blob/main/_autodocs/prepared-statements.md Executes the prepared statement with the provided arguments and returns result rows. ```go stmt, err := conn.PrepareContext(ctx, "SELECT id, name FROM users WHERE id > ?") if err != nil { panic(err) } defer stmt.Close() rows, err := stmt.Query([]driver.NamedValue{{Value: int32(100)}}) if err != nil { panic(err) } defer rows.Close() for rows.Next() { var id int32 var name string if err := rows.Scan(&id, &name); err != nil { panic(err) } fmt.Printf("id=%d, name=%s\n", id, name) } ```