RATIONAL, VECTOR ou INET, que funcionam com ORDER BY, índices e funções de agregação. O SDK Rust oferece suporte a isso por meio da macro custom_type! e, para tipos cujo tamanho de armazenamento depende de parâmetros de coluna, por meio de parameterized_type! (consulte Tipos parametrizados).
Esta página pressupõe que você já tenha trabalhado com Criando Extensões em Rust. A configuração (Cargo.toml, manifest.json, cargo-vsql) é a mesma.
Quando usar um tipo personalizado
Use um tipo personalizado quando:- Você precisar de um layout binário em disco que um tipo SQL padrão não consegue expressar (floats compactados, inteiros de largura fixa, identificadores binários)
- Seu tipo tiver semântica de ordenação própria que difere da ordenação lexicográfica de strings
- Você quiser que o servidor indexe e faça hash dos valores corretamente para
ORDER BY,GROUP BY,DISTINCTe operações de conjunto
STRING, INT ou REAL, você não precisa de um tipo personalizado.
A macro custom_type!
Todo tipo personalizado precisa de 3 callbacks (encode, decode, compare), um valor padrão e, opcionalmente, um callback de hash. Aqui está a assinatura completa da macro:type_name, persisted_length, max_decode_buffer_length, encode, decode e compare são obrigatórios. hash é opcional, mas recomendado, porque GROUP BY, DISTINCT e as operações de conjunto corretos dependem dele. Dê ao tipo um padrão de uma forma ou de outra: default para um valor que você consegue escrever como literal, intrinsic_default_fn para um que a extensão precisa calcular. Definir ambos faz o INSTALL EXTENSION falhar. Não definir nenhum deixa a extensão ser instalada e, então, faz falhar a primeira instrução que nomeia o tipo.
Recebendo e retornando valores binários
Funções que recebem ou retornam um tipo personalizado trabalham com bytes brutos. Entrada —InValue::Custom(b) carrega o binário armazenado como &[u8]:
VdfReturn::Binary(bytes) envia bytes binários de volta ao servidor:
func!, use villagesql::custom!("type_name"):
Exemplo: tipo de número racional
examples/vsql_rational no repositório do SDK é uma extensão funcional que implementa um tipo RATIONAL. Ela armazena um número racional como um par de valores i64 (numerador, denominador, totalizando 16 bytes) em ordem de bytes little-endian e fornece funções aritméticas.
Aqui estão as implementações principais de encode, decode, compare e hash:
custom_type!, os auxiliares gcd e normalize que rational_encode chama, e as VDFs aritméticas (rational_add, rational_sub, etc.) estão no código-fonte completo em examples/vsql_rational/src/lib.rs.
Com a extensão instalada:
rational_to_real(r RATIONAL) -> REAL converte um valor RATIONAL em uma aproximação de ponto flutuante de 64 bits, dividindo o numerador pelo denominador. Útil quando você precisa de um decimal aproximado para exibição ou comparação, mas não quer armazenar a representação com perda na coluna.
Tipos parametrizados
Um tipo parametrizado precisa de um valor lido no momento doCREATE TABLE — como
o 3 em VECTOR(3) — para saber seu tamanho de armazenamento. custom_type! não
consegue expressar isso: seu persisted_length é uma única constante fixa para toda
coluna. parameterized_type! é a contraparte parametrizada: o comprimento persistido
é calculado por coluna a partir dos parâmetros declarados, através de int_to_params
e resolve_params, em vez de ser fixo.
type_name, max_persisted_length, max_decode_buffer_length, encode, decode, compare, int_to_params, resolve_params, params_type, params_parse e params_to_strings são obrigatórios. hash é opcional. Dê ao tipo um padrão de uma forma ou de outra: default para um valor que você consegue escrever como literal, intrinsic_default_fn (uma função que calcula o padrão a partir de &P, para quando o padrão depende dos parâmetros) para um que a extensão precisa calcular. Definir ambos faz o INSTALL EXTENSION falhar. Não definir nenhum deixa a extensão ser instalada e, então, faz falhar a primeira instrução que nomeia o tipo.
Aqui está padint — um i64 armazenado em 8 bytes fixos, com um parâmetro width que controla a largura de exibição preenchida com zeros:
InValue::CustomWithParams { bytes, params } em vez do simples
InValue::Custom(bytes) — params é um TypeParams, uma visão somente de
leitura e sem cópia sobre os pares key=value declarados da coluna.
O bloco extension! com tipos
Ao registrar tanto funções quanto tipos, o blocoextension! tem duas seções:
types:. Uma extensão que contém apenas tipos mantém funcs: [] e não omite mais nada.
Próximos passos
Referência da API Rust
Referência para InValue, VdfReturn e as macros extension!, func!, agg_func!, varargs_func!, custom_type! e custom!.
Criando Extensões em Rust
Primeiros passos — configuração do Cargo, primeira função, empacotamento e testes.
Tipos Personalizados em C++
Tipos personalizados em C++ —
make_type<>, encode/decode/compare/hash, regras de ALTER TABLE.Arquitetura de Extensões
Como tipos personalizados são resolvidos, armazenados em cache e persistidos.

