Skip to main content
O SDK Rust está em alfa — espere mudanças incompatíveis na API entre versões. Extensões que contêm apenas funções e tipos personalizados (encode, decode, compare, hash) têm suporte. Agregações, prerun(), VarArgs, variáveis de sistema e de status, acesso ao keyring e a ABI de armazenamento em coluna são exclusivos de C++ hoje — use o Criando Extensões em C++ se você precisar de qualquer um deles.
Tipos personalizados permitem que você defina novos tipos de coluna, como 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!. 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, COUNT(DISTINCT) e operações de conjunto
Se você precisar apenas de funções chamáveis via SQL e seus dados couberem confortavelmente em colunas STRING, INT ou REAL, você não precisa de um tipo personalizado.

A macro custom_type!

Todo tipo personalizado precisa de 4 callbacks (encode, decode, compare, hash) e um valor padrão. Aqui está a assinatura completa da macro:
type_name, persisted_length, max_decode_buffer_length, encode, decode e compare são obrigatórios. hash e default são opcionais, mas recomendados — hash é necessário para que o COUNT(DISTINCT) e as operações de conjunto funcionem corretamente, e default é necessário para a verificação de inicialização do tipo.

Recebendo e retornando valores binários

Funções que recebem ou retornam um tipo personalizado trabalham com bytes brutos. EntradaInValue::Custom(b) carrega o binário armazenado como &[u8]:
SaídaVdfReturn::Binary(bytes) envia bytes binários de volta ao servidor:
Para referenciar um tipo personalizado em uma declaração 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:
O registro custom_type! 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.

O bloco extension! com tipos

Ao registrar tanto funções quanto tipos, o bloco extension! tem duas seções:
Qualquer uma das seções pode ser omitida se estiver vazia. Uma extensão que contém apenas tipos omite funcs:; uma extensão que contém apenas funções omite types:.

Próximos passos

Referência da API Rust

Referência completa para InValue, VdfReturn e todas as macros.

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.