← Files VillageSQL SkillsARCHIVED FILE

skills/vsql-extension-builder/references/capabilities.md

4.65 KB · Oct 4, 2026 · 12:20 UTC

↓ Download file

# VEF Capability Discovery

Do not assume limitations from prior knowledge. Probe the SDK and the
running server.

## Header-discoverable (Phase 2 bootstrap)

Assess all capabilities from the typed API headers (`vsql.h` and the
`vsql/` subdirectory).

- **Storage model.** Does the type builder expose only fixed-length
  storage, or also variable-length? For fixed-length, the persisted length
  sets the storage size and encode must write exactly that many bytes;
  returning 0 via the length output parameter signals an error.

  **If only fixed-length storage is available** and the type is
  inherently variable in size (e.g., hstore, JSON-like, packed lists),
  apply this workaround — only if the probe above confirms no
  variable-length API exists:
  1. Size `persisted_length` to your practical maximum (e.g., the largest
     valid value the type accepts).
  2. In encode: write the real data, then zero-pad to fill exactly
     `persisted_length` bytes. Encode must write exactly that count.
  3. Embed an in-band header at a fixed offset (e.g., a 2- or 4-byte
     byte count at the start) so decode knows where real data ends.
  4. In decode: read the in-band length, then process only that many
     bytes — ignore the zero padding.
  5. Document this constraint in README under Known Limitations, naming
     the VEF capability that would remove the need for it.

- **Parameterized types.** Does the SDK expose registration functions for
  types that accept `TYPE(N)` or `TYPE('key=value')` arguments? Look for
  two registration flavors (integer shorthand and key=value string) and
  the struct that carries parameter data from server to extension. Record
  exact names. The canonical example is
  `villagesql/examples/vsql-tvector/src/tvector.cc` in the server source
  tree.

- **Index registration.** Is an index registration API present? If not,
  custom type columns cannot be indexed — do not design around index-based
  lookup.

- **Max VDF parameters.** Read the max-parameter constant. Functions
  needing more inputs must use structured types or be split.

- **Preview capabilities.** Headers under a `preview/` subdirectory are
  preview capabilities — documented but unstable across server builds.
  Read what is actually present; do not assume specific APIs exist. If a
  preview API would meaningfully improve the implementation, present the
  trade-off to the user (see Phase 2 step 2f). Record any preview API use
  in `.claude/tracking/limitations.md` so it surfaces in the README.

## Behavior-discoverable (after first install in Phase 3)

These can't be probed in Phase 1 because no extension is installed yet.
Run them as part of Phase 3 once the extension is built and installed for
the first time, and record results in `.claude/tracking/limitations.md`.

- **Aggregate functions.** Create a custom type column and test `SUM` or
  `AVG`. If they fail, only `COUNT(DISTINCT)`, `MIN`, `MAX`, and
  `GROUP_CONCAT` are safe — document this constraint.

- **Extension upgrade path.** Test `ALTER EXTENSION` or equivalent. If it
  doesn't exist, type changes require `UNINSTALL` + `INSTALL` — document
  for users.

- **REAL-returning functions with integer input.** If the extension includes
  a `.returns(REAL)` function, test it with an INT column and inspect the
  result type via `DESCRIBE`. If it shows INT rather than DOUBLE, document
  the `CAST(col AS DOUBLE)` or `col * 1.0` workaround, record the limitation,
  and link [villagesql-server#608](https://github.com/villagesql/villagesql-server/issues/608).

- **STRING return size and charset.** VDF STRING results are subject to two
  current behaviors that affect any function returning text:
  1. **256-byte cap.** The SDK truncates STRING returns to the server's
     `max_str_len` (currently 256 bytes). Test with a function that builds
     a string longer than 256 bytes and check whether the result is
     silently truncated. If the extension needs to return larger payloads
     (e.g. a JSON array of many values), design around the cap — chunked
     enumeration, prefix-filtered queries, or splitting across multiple
     calls. Track villagesql-server
     [#641](https://github.com/villagesql/villagesql-server/issues/641)
     and [#343](https://github.com/villagesql/villagesql-server/issues/343).
  2. **Binary charset.** STRING results are tagged `binary`, so MySQL
     JSON functions (`JSON_EXTRACT`, `JSON_TABLE`, etc.) reject them
     without an explicit `CONVERT(... USING utf8mb4)`. Test by piping a
     result through a JSON function and document the `CONVERT` step in
     the README if users will consume the output as JSON. Track
     villagesql-server
     [#612](https://github.com/villagesql/villagesql-server/issues/612).

SHA-256: d4849b490d05404cf3c08c7c4c17f6b60cdd04b312a3dbb73622ef0c919fb196