> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Rust SDK API Reference

> Complete reference for the VillageSQL Rust SDK — InValue, VdfReturn, extension!, func!, custom_type!, custom!, and manifest.json fields.

> [!NOTE]
>
> The Rust SDK is at version 0.0.1.

This page is a reference for the `villagesql` crate API. For the getting started tutorial, see [Building Extensions in Rust](https://villagesql.com/docs/en/8.4/0.0.4/rust-sdk.md). For custom types, see [Custom Types in Rust](https://villagesql.com/docs/en/8.4/0.0.4/rust-custom-types.md).

## InValue

`InValue` is the enum the server passes for each function argument. Your function receives `args: &[InValue]` and must check each argument before using its value.

```rust theme={null}
pub enum InValue<'a> {
    String(&'a str),
    Real(f64),
    Int(i64),
    Null,
    Custom(&'a [u8]),
}
```

| Variant | Rust type | Corresponding SQL type |
| - | - | - |
| `String(&str)` | UTF-8 string slice | `STRING` / `VARCHAR` / `TEXT` |
| `Real(f64)` | 64-bit float | `REAL` / `DOUBLE` / `FLOAT` |
| `Int(i64)` | 64-bit signed integer | `INT` / `BIGINT` / `TINYINT` |
| `Null` | — | SQL `NULL` for any type |
| `Custom(&[u8])` | Raw binary bytes | Any custom type registered via `custom_type!` |

Always match on `Null` explicitly. Calling `.unwrap()` or pattern-matching only the value variants is a bug — SQL NULL is a normal input, not an error.

## VdfReturn

`VdfReturn` is what your function returns to the server. Construct it with one of the associated functions:

| Constructor | SQL effect |
| - | - |
| `VdfReturn::null()` | Returns SQL NULL for this row |
| `VdfReturn::string(s)` | Returns a `String` value; `s` is `impl Into<String>` |
| `VdfReturn::real(v)` | Returns an `f64` value |
| `VdfReturn::int(v)` | Returns an `i64` value |
| `VdfReturn::binary(bytes)` | Returns binary bytes for a custom type column; `bytes` is `Vec<u8>` |
| `VdfReturn::warning(msg)` | Returns NULL for this row, adds a SQL warning, execution continues |
| `VdfReturn::error(msg)` | Aborts the statement with a fatal error |

**Warning vs error:**

Use `warning` for user-input validation failures where continuing with the rest of the result set makes sense. In strict mode, MySQL promotes warnings to errors on `INSERT` and `UPDATE`. Use `error` for conditions where proceeding is unsafe — corrupt stored data, internal invariant violations. A fatal error aborts the entire statement.

```rust theme={null}
fn validate_impl(args: &[InValue]) -> VdfReturn {
    match args.first() {
        Some(InValue::Int(n)) if *n >= 0 => VdfReturn::int(*n),
        Some(InValue::Int(_)) => VdfReturn::warning("value must be non-negative"),
        Some(InValue::Null) | None => VdfReturn::null(),
        _ => VdfReturn::error("validate: expected an INT argument"),
    }
}
```

## extension! macro

`extension!` generates the VEF entry points the server calls when loading your VEB file. It must appear exactly once in the crate.

```rust theme={null}
villagesql::extension! {
    funcs: [
        // One or more villagesql::func!(...) declarations
    ],
    types: [
        // One or more villagesql::custom_type!(...) declarations
    ]
}
```

Both sections are optional. A pure-function extension omits `types:`; a type-only extension omits `funcs:`. An empty `extension!` block (no funcs, no types) is valid but produces an extension that does nothing.

## func! macro

`func!` declares a SQL-callable function. Positional arguments:

```rust theme={null}
villagesql::func!(rust_fn, "sql_name", [param_types] -> return_type)
villagesql::func!(rust_fn, "sql_name", [param_types] -> return_type, deterministic: true)
```

| Argument | Description |
| - | - |
| `rust_fn` | The Rust function implementing the VDF. Signature: `fn(&[InValue]) -> VdfReturn`. |
| `"sql_name"` | The SQL function name as a string literal. This is what users call from SQL. |
| `[param_types]` | Comma-separated list of `villagesql::Type::*` or `villagesql::custom!("name")` values. Use `[]` for zero-arity functions. |
| `return_type` | `villagesql::Type::*` or `villagesql::custom!("name")`. |
| `deterministic: true` | Optional. Declares the function deterministic — same inputs always produce the same output, no side effects. The optimizer can cache results for identical inputs. Only set this when it's true. |

**Type constants** for use in `func!`:

| `villagesql::Type::*` | SQL type |
| - | - |
| `villagesql::Type::String` | `STRING` |
| `villagesql::Type::Real` | `REAL` |
| `villagesql::Type::Int` | `INT` |

## custom\_type! macro

`custom_type!` registers a new column type. `type_name`, `persisted_length`, `max_decode_buffer_length`, `encode`, `decode`, and `compare` are required. `hash` and `default` are optional but recommended.

```rust theme={null}
villagesql::custom_type!(
    type_name: "sql_type_name",
    persisted_length: N,
    max_decode_buffer_length: M,
    encode: encode_fn,
    decode: decode_fn,
    compare: compare_fn,
    hash: hash_fn,
    default: "default_string",
)
```

| Field | Type | Description |
| - | - | - |
| `type_name` | `&str` literal | SQL name for the type. Case-insensitive in SQL. Must be unique among all installed extensions. |
| `persisted_length` | `usize` | Fixed byte length for on-disk storage. All encoded values must produce exactly this many bytes. |
| `max_decode_buffer_length` | `usize` | Maximum byte length of the decoded string. Used to size the output buffer before calling `decode`. |
| `encode` | `fn(&str) -> Result<Vec<u8>, String>` | Called at `INSERT` time. Converts a SQL string literal to binary. Return `Err(msg)` to reject the input. |
| `decode` | `fn(&[u8]) -> Result<String, String>` | Called to display the value. Converts binary back to a string. |
| `compare` | `fn(&[u8], &[u8]) -> std::cmp::Ordering` | Called for `ORDER BY`, `MIN`, `MAX`. Return `Less`, `Equal`, or `Greater`. |
| `hash` | `fn(&[u8]) -> usize` | Optional. Called for `COUNT(DISTINCT)` and set operations. Values that compare `Equal` must hash to the same value. Recommended for indexed columns. |
| `default` | `&str` literal | Optional. A valid string the server encodes at type initialization to verify the callback works. Must encode to exactly `persisted_length` bytes. |

The `default` field is not a column default value — it's a startup probe. The server calls `encode(default)` when loading the extension to verify the callback works. If `encode` returns `Err` for the default, the extension fails to load.

## custom! macro

`villagesql::custom!("type_name")` references a custom type by name in a `func!` declaration:

```rust theme={null}
villagesql::func!(
    my_fn,
    "my_sql_func",
    [villagesql::custom!("mytype")] -> villagesql::custom!("mytype"),
    deterministic: true
)
```

Use it anywhere a `villagesql::Type::*` would appear in a parameter list or return type position. The string must match the `type_name` declared in the corresponding `custom_type!`.

## manifest.json fields

Every extension needs a `manifest.json` alongside its `Cargo.toml`:

```json theme={null}
{
  "name": "vsql_my_extension",
  "version": "0.1.0",
  "description": "Brief description of what the extension does",
  "author": "Your Name",
  "license": "GPL-2.0"
}
```

| Field | Required | Format | Description |
| - | - | - | - |
| `name` | Yes | lowercase letters, digits, `_`, `-` | Extension identifier. Must match the `INSTALL EXTENSION` name. Use underscores — hyphens require backtick quoting in SQL. |
| `version` | Yes | MAJOR.MINOR.PATCH | Semantic version. |
| `description` | No | String | Shown in `INFORMATION_SCHEMA.EXTENSIONS`. |
| `author` | No | String | Author name or organization. |
| `license` | No | String | License identifier. `GPL-2.0` recommended for open-source extensions. |

`name` validation rules: must start with a letter, end with a letter or digit, max 64 characters. An invalid manifest causes `INSTALL EXTENSION` to fail.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.