|
| 1 | +# DuckGo: Create DuckDB UDFs in Go/XGo with Ease |
| 2 | + |
| 3 | +[](https://pkg.go.dev/github.com/ma6174/duckgo) |
| 4 | + |
| 5 | +`DuckGo` is a Go library designed to dramatically simplify the process of creating User-Defined Functions (UDFs) for [DuckDB](https://duckdb.org/). It uses Go's reflection mechanism to seamlessly convert a native Go function into a DuckDB scalar UDF. Additionally, it leverages [ixgo](https://github.com/goplus/ixgo) to support dynamically loading UDFs from Go/XGo scripts without prior compilation. |
| 6 | + |
| 7 | +## Core Features |
| 8 | + |
| 9 | +- **Create from Native Go Functions**: Directly convert your Go functions (e.g., `func(a, b int) int`) into DuckDB UDFs. |
| 10 | +- **Automatic Type Mapping**: Automatically handles type conversions between Go and DuckDB, supporting a wide range of data types. |
| 11 | +- **Variadic Function Support**: Seamlessly supports Go's variadic functions. |
| 12 | +- **Dynamic Script Loading**: No compilation needed! Directly load functions from `.go` or `.xgo` source files as UDFs. |
| 13 | +- **Direct Loading from SQL**: Provides a helper function to load and register UDFs from scripts directly within SQL queries. |
| 14 | +- **Panic Handling**: Gracefully recovers from panics during UDF execution and converts them into DuckDB errors. |
| 15 | + |
| 16 | +## Installation |
| 17 | + |
| 18 | +```bash |
| 19 | +go get github.com/ma6174/duckgo |
| 20 | +``` |
| 21 | + |
| 22 | +## Important Note: Regarding Dynamic Scripting |
| 23 | + |
| 24 | +The dynamic script loading feature (provided by the `script` package) relies on [ixgo](https://github.com/goplus/ixgo). Due to how `ixgo` works, you **must** add a specific linker flag to disable symbol name checking whenever you build or run code that uses the `script` package. |
| 25 | + |
| 26 | +Failure to do so will result in a linker error. |
| 27 | + |
| 28 | +**Build:** |
| 29 | +```bash |
| 30 | +go build -ldflags="-checklinkname=0" . |
| 31 | +``` |
| 32 | + |
| 33 | +**Run:** |
| 34 | +```bash |
| 35 | +go run -ldflags="-checklinkname=0" . |
| 36 | +``` |
| 37 | + |
| 38 | +If you import the `script` package in your own project, make sure to include this flag in your build and run commands. |
| 39 | + |
| 40 | +## Usage |
| 41 | + |
| 42 | +Here are a few examples of how to use `DuckGo`. For complete, runnable code, please see the [`example`](./example) directory. |
| 43 | + |
| 44 | +### Example 1: Creating a UDF from a Native Go Function |
| 45 | + |
| 46 | +This is the most basic use case. Any regular Go function can be registered. |
| 47 | + |
| 48 | +The core logic involves wrapping the native Go function with `udf.BuildScalarUDF` and then registering it using `duckdb.RegisterScalarUDF`. |
| 49 | + |
| 50 | +**For the full code, see: [`example/simple_udf/main.go`](./example/simple_udf/main.go)** |
| 51 | + |
| 52 | +### Example 2: Loading a UDF from a Go Script |
| 53 | + |
| 54 | +This is one of `DuckGo`'s most powerful features. You can register a function from a Go source file as a UDF without compiling it first. |
| 55 | + |
| 56 | +The `script.AddIXGoUDFFromFile` function allows you to specify a `.go` file and the names of the functions you want to load. |
| 57 | + |
| 58 | +**For the full code, see: [`example/script_udf/`](./example/script_udf/)** |
| 59 | + |
| 60 | +### Example 3: Loading a UDF Directly via SQL |
| 61 | + |
| 62 | +For even greater flexibility, you can call a helper function from within SQL to load UDFs. |
| 63 | + |
| 64 | +First, enable the feature by calling `script.EnableRegisterUDFFromSQL(db)`. You can then use the `add_ixgo_udf` function in your SQL queries. |
| 65 | + |
| 66 | +**For the full code, see: [`example/sql_load_udf/`](./example/sql_load_udf/)** |
| 67 | + |
| 68 | +## Package Overview |
| 69 | + |
| 70 | +- **`udf`**: The core package, responsible for converting native Go functions into DuckDB UDFs. |
| 71 | +- **`script`**: Provides the functionality for dynamically loading UDFs from Go/XGo scripts. |
| 72 | + |
| 73 | +## License |
| 74 | + |
| 75 | +This project is licensed under the [MIT](LICENSE) License. |
0 commit comments