Skip to main content
The VillageSQL Extension Framework (VEF) calls extension code at prescribed places in the MySQL server code. Everything that happens to the extension’s output — crash recovery, replication, schema operations, backups — is handled by the server the same way it handles any built-in column type. This document describes that boundary: what the VEF does, what extensions do, and how the resulting system behaves in operation. Examples throughout this page use the vsql-uuid extension to illustrate how data flows.

The ABI boundary

VillageSQL extensions interact with the server through a binary interface (ABI) with a clear separation of ownership between the extension and server. The server owns:
  • Storage: InnoDB reads and writes bytes; it doesn’t interpret them
  • Schema: column type metadata and which extension registered each type are stored in the VillageSQL system tables and persist across restarts
  • Recovery, replication, and backups: these operate on raw bytes, the same as any built-in column type
  • Extension registration: names, versions, and function/type registrations are reloaded from the VillageSQL system tables at startup
The extension owns:
  • Binary format: the from_string encode function defines what gets written to disk; to_string reads it back during output
  • Business rules: validation, comparison, hashing, and error handling
  • State: extensions don’t persist anything outside the bytes the server stores for them
For the full binary interface — structs, function pointer typedefs, and protocol versioning — see villagesql/sdk/include/villagesql/abi/types.h in the server repository.

How custom types are stored

When you declare a column as UUID (as an example from vsql-uuid), the server stores a fixed-length block of raw bytes per row. The human-readable form — like d7d665f3-bb13-4c2f-b10f-d2126eb40cba — exists only at the boundaries: from_string encodes it to binary on write, and to_string decodes it back on read. Everything in between — storage, redo log, crash recovery, binary log — operates on those bytes without interpreting them.

Crash recovery

Extensions reload automatically on server restart — no manual intervention is required. You can verify this via INFORMATION_SCHEMA.EXTENSION_REGISTRATION, which shows the same registration entry after restart as before. Row data survives through InnoDB’s normal crash recovery. The extension’s binary format is never special-cased — InnoDB handles a UUID column no differently from a VARBINARY column.

Binary log format

In row-format replication (the default), custom type values travel as raw binary in the binary log. There is no re-encoding step: the extension’s from_string is not called when writing the binlog, and to_string is called only when a client reads the value back. A row-level binary log entry for a UUID column looks like this:
Those 16 raw bytes flow through the binary log unchanged. A consumer with the extension installed can decode them to the readable value via to_string; one without it — an external CDC pipeline or binlog reader — sees only the raw bytes.

Restore

Restoring a VillageSQL server works the same way as crash recovery: the server starts up, reads its extension registrations, and loads each extension automatically. No special handling is needed for extension-typed columns — the raw bytes are in the backup, and the extensions decode them on demand. Extensions are not stored inside the database — they live as .veb files in veb_dir on disk. If the VEB file is missing when the server starts on the restored instance, startup aborts with VEB file not found. The .veb_expansion_cache is not a substitute for the .veb itself. When distributing your extension, make sure your users know to include veb_dir in any backup or server migration alongside the data directory.

Schema operations

ALTER TABLE on tables with extension-typed columns behaves exactly as it does for built-in types. The server tracks the column’s extension binding in its schema metadata, and that binding survives the table rebuild. Adding or modifying other columns on a table with a vsql-uuid id column leaves the UUID data intact.