Skip to main content

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 is the original VEF interface. It is stable as of v0.0.1 and likely to be deprecated in a future release. New extensions should use the Protocol 2 API — the template-based type builders in the Creating Extensions and 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 2 equivalents — they take raw pointers and lengths rather than Span<> and std::string_view.

Function Signatures

// 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.
}
The bool return convention (false = success, true = error) is explained in Part B of Critical API Contracts.

Registration

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())
);
Note that make_type(MYTYPE) (no template parameter) is the Protocol 1 form. The Protocol 2 form is vsql::make_type<kMyTypeName>() with a compile-time string NTTP.

Raw ABI Style (Functions)

Protocol 1 VDF implementations can pass the raw C structs directly instead of using typed wrappers. This style is supported but typed wrappers are preferred for new code.
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 wrapper approach — the builder detects the signature automatically.

Raw ABI Aggregate Approach

For aggregates, the raw ABI exposes prerun, postrun, clear, and accumulate with their full C signatures. Prefer the typed aggregate approach for new code.
make_func<&raw_result>("my_agg")
    .returns(INT).param(INT)
    .prerun<&my_prerun>()      // void(vef_context_t*, vef_prerun_args_t*, vef_prerun_result_t*)
    .postrun<&my_postrun>()    // void(vef_context_t*, vef_postrun_args_t*, vef_postrun_result_t*)
    .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()