> ## 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.

# Protocol 1 API

> Reference for the Protocol 1 function-pointer type API and raw ABI style — the original VEF interface, stable as of v0.0.1 and will be dropped after 0.0.5.

Protocol 1 is the original VEF interface. It was stable as of v0.0.1 and will be dropped after 0.0.5. New extensions should use the Protocol 3 API — the template-based type builders in the [Creating Extensions in C++](/mysql-8.4/0.0.5/create) and [C++ Development](/mysql-8.4/0.0.5/development) guides.

This page exists for reference when working with existing extensions built against Protocol 1.

## Function-Pointer Type API

Protocol 1 custom types are registered using explicit function pointers instead of the `vsql::make_type<>` template. The function signatures differ from the Protocol 3 equivalents — they take raw pointers and lengths rather than `Arg` and `Result` objects.

### Function Signatures

```cpp theme={null}
// Encode: Convert string representation to binary.
// Returns false on success, true on error.
bool encode_mytype(unsigned char* buffer, size_t buffer_size,
                   const char* from, size_t from_len, size_t* length) {
    // Parse 'from' string and write binary to 'buffer'.
    // Set *length to bytes written.
    // Return false on success, true on error (e.g., set *length = 0).
}

// Decode: Convert binary to string representation.
// Returns false on success, true on error.
bool decode_mytype(const unsigned char* buffer, size_t buffer_size,
                   char* to, size_t to_size, size_t* to_length) {
    // Read binary from 'buffer' and write string to 'to'.
    // Set *to_length to string length.
    // Return false on success, true on error.
}

// Compare: enables ORDER BY and indexing (required).
int compare_mytype(const unsigned char* data1, size_t len1,
                   const unsigned char* data2, size_t len2) {
    // Return: negative if data1<data2, 0 if equal, positive if data1>data2.
}

// Hash: custom hash (optional, uses default binary hash if omitted).
size_t hash_mytype(const unsigned char* data, size_t len) {
    // Return hash value for the binary data.
}
```

### Registration

```cpp theme={null}
VEF_GENERATE_ENTRY_POINTS(
  make_extension()
    .type(make_type(MYTYPE)
      .persisted_length(16)              // Fixed storage size in bytes
      .max_decode_buffer_length(64)      // Max string representation size
      .encode(&encode_mytype)
      .decode(&decode_mytype)
      .compare(&compare_mytype)          // Enables ORDER BY and indexes
      .hash(&hash_mytype)                // Optional custom hash
      .build())
    .func(make_func<&mytype_constructor>("MYTYPE")  // Constructor function
      .returns(MYTYPE)
      .param(REAL)
      .param(REAL)
      .build())
);
```

`vsql::make_type<kMyTypeName>()` (with a compile-time string NTTP) is the preferred form. `make_type(MYTYPE)` (no template parameter) is the Protocol 1 form — support for it will be dropped after 0.0.5.

## Raw ABI Style (Functions)

Protocol 1 VDF implementations can pass the raw C structs directly instead of using typed wrappers. This style will be dropped after 0.0.5 — use the [typed argument/result API](/mysql-8.4/0.0.5/development#argument-and-result-types) for all new code.

```cpp theme={null}
void add_impl(vef_context_t* ctx,
              vef_invalue_t* a, vef_invalue_t* b,
              vef_vdf_result_t* result) {
  result->int_value = a->int_value + b->int_value;
  result->type = VEF_RESULT_VALUE;
}
```

Registration is identical to the typed approach — the builder detects the signature automatically.

### Result Constants

The raw ABI communicates result state via `vef_return_value_type_t` set on `result->type`:

| Constant             | Value | Meaning                                                                                                                                                         |
| -------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `VEF_RESULT_VALUE`   | 0     | Success — the output is in the appropriate union field                                                                                                          |
| `VEF_RESULT_NULL`    | 1     | The result is SQL NULL                                                                                                                                          |
| `VEF_RESULT_WARNING` | 2     | Row-level warning — execution continues, NULL is returned for this row, a SQL warning is added; in strict mode MySQL promotes this to an error on INSERT/UPDATE |
| `VEF_RESULT_ERROR`   | 3     | Fatal error — statement execution is aborted; message is in `result->error_msg`                                                                                 |

In Protocol 3, `out.set()`, `out.set_null()`, `out.warning()`, and `out.error()` handle this automatically.

### Aggregate Registration in Protocol 1

For aggregates, `.clear<>()` and `.accumulate<>()` accept raw ABI function pointer signatures. `.prerun<>()` and `.postrun<>()` do not — the builder requires typed signatures (`void(PrerunArgs, PrerunResult)` and `void(PostrunArgs)`) even for Protocol 1 extensions. Use the [typed aggregate approach](/mysql-8.4/0.0.5/development#aggregate-vdfs) for all new code.

```cpp theme={null}
make_func<&raw_result>("my_agg")
    .returns(INT).param(INT)
    // prerun/postrun require typed signatures even in Protocol 1 mode:
    .prerun<&my_prerun>()      // void(vsql::PrerunArgs, vsql::PrerunResult)
    .postrun<&my_postrun>()    // void(vsql::PostrunArgs)
    .clear<&my_clear>()        // void(vef_context_t*, vef_vdf_args_t*)
    .accumulate<&my_acc>()     // void(vef_context_t*, vef_vdf_args_t*, vef_vdf_result_t*)
    .build()
```
