Skip to main content
O SDK Rust está em alpha — espere mudanças incompatíveis de API entre versões. Extensões apenas de funções, funções de agregação, funções varargs e tipos personalizados (encode, decode, compare, hash) são compatíveis, assim como as capabilities Preview sys_var, status_var, thread_worker e keyring. A ABI de armazenamento de coluna é exclusiva do C++ hoje — use o SDK C++ se você precisar dela.
Esta página é uma referência da API do crate villagesql. Para o tutorial de introdução, consulte Criando Extensões em Rust. Para tipos personalizados, consulte Tipos Personalizados em Rust.

InValue

InValue é o enum que o servidor passa para cada argumento de função. Sua função recebe args: &[InValue] e deve verificar cada argumento antes de usar seu valor.
Sempre faça a correspondência de Null explicitamente. Chamar .unwrap() ou fazer a correspondência de padrão apenas das variantes de valor é um bug — o NULL do SQL é uma entrada normal, não um erro.

VdfReturn

VdfReturn é o que sua função retorna ao servidor. Construa-o com uma das funções associadas: Aviso vs. erro: Use warning para falhas de validação de entrada do usuário em que faz sentido continuar com o restante do conjunto de resultados. No modo estrito, o MySQL promove avisos a erros em INSERT e UPDATE. Use error para condições em que prosseguir é inseguro: dados armazenados corrompidos, violações de invariantes internas. Um erro fatal aborta a instrução inteira.

macro extension!

extension! gera os pontos de entrada VEF que o servidor chama ao carregar seu arquivo VEB. Ele deve aparecer exatamente uma vez no crate.
types: e requires: são opcionais por si só, mas funcs: deve estar sempre presente — escreva funcs: [] para uma extensão apenas de tipos. Uma extensão apenas de funções omite types:. Um bloco extension! com funcs: [] e sem tipos é válido, mas produz uma extensão que não faz nada. requires: declara as capabilities Preview que a extensão usa, como referências a objetos static de capability. Ela deve vir por último, depois de uma seção funcs: — inclua funcs: [] se a extensão não registrar nenhuma função.

macro func!

func! declara uma função chamável via SQL. Seis formas — quatro sem estado por instrução (sem parâmetros, apenas buffer_size, apenas deterministic, ambos) e duas que anexam estado por instrução por meio de uma função prerun:
O parâmetro buffer_size requer o crate villagesql 0.0.2 ou posterior. A versão atual do crates.io (0.0.1) não o expõe — até que o 0.0.2 seja lançado, use as formas sem buffer_size.
Constantes de tipo para uso em func!:

Estado por instrução

Algumas funções precisam de um estado que abrange todas as linhas de uma única instrução — um contador de chamadas, um acumulador. Declare o tipo do estado com state: e uma função de configuração com prerun:. A função prerun é executada uma vez, antes da primeira linha; a função de linha então é executada uma vez por linha com acesso &mut a esse estado. Uma função prerun tem a assinatura fn(PrerunArgs, PrerunResult<T>), e a função de linha que ela alimenta recebe o estado primeiro: fn(state: &mut T, args: &[InValue]) -> VdfReturn. T é o tipo nomeado por state:, e o compilador verifica se a prerun e a função de linha concordam sobre ele. PrerunArgs::len() é o número de argumentos que cada linha vai receber, e PrerunArgs::is_empty() é verdadeiro quando a função foi chamada sem argumentos. Você não deve liberar o estado por conta própria: func! gera a postrun que o descarta quando a instrução termina. Isso é o oposto do SDK C++, onde sua postrun tem que chamar delete_state<T>() — consulte Estado por Instrução.
Os parâmetros state e prerun ainda não estão em uma versão publicada. A versão atual do crates.io (0.0.1) não os expõe.
Uma extensão completa cuja função retorna o próprio índice de chamada dentro da instrução:
Compile e instale a extensão conforme descrito em Criando Extensões em Rust, e então:
A tabela tem três linhas, então call_index() é executada três vezes e retorna 1, depois 2, depois 3 — um valor por linha. SUM soma esses três valores, o que dá 6. O segundo SELECT retorna o mesmo total do primeiro, não um maior: o contador é alocado para uma instrução e descartado quando ela termina.

macro agg_func!

agg_func! declara uma função SQL de agregação — no estilo de SUM/COUNT, chamada sobre as linhas de cada grupo em vez de uma vez por linha. Duas formas:
agg_func! ainda não está em uma versão publicada. A versão atual do crates.io (0.0.1) não o expõe.
O acumulador é alocado uma vez por instrução e descartado quando a instrução termina — agg_func! gera tanto a prerun que o cria quanto a postrun que o descarta, então você nunca escreve nenhuma das duas. clear_fn é o que dá a você o comportamento por grupo: com GROUP BY, o mesmo acumulador é reutilizado entre os grupos, então qualquer campo que não deva vazar entre grupos tem que ser redefinido ali. Uma agregação completa equivalente a SUM — o exemplo vsql_agg_sum no repositório do SDK:
accumulate fazer a correspondência apenas de InValue::Int é o que pula os NULLs, correspondendo ao SUM embutido. O flag seen é o que faz um grupo todo de NULLs e um grupo vazio retornarem NULL em vez de 0:

macro varargs_func!

varargs_func! declara uma VDF que aceita qualquer número de argumentos, de qualquer tipo. A lista de parâmetros é escrita [..] — um literal obrigatório, não o [] usado para uma func! de aridade zero.
O servidor não realiza nenhuma validação de contagem nem de tipo de argumentos para uma VDF varargs. Não há uma lista de parâmetros declarada contra a qual verificar uma chamada, então toda chamada chega à sua função com o que quer que o texto SQL tenha passado, incluindo zero argumentos e tipos que você nunca esperou. A validação é inteiramente trabalho do gancho prerun. O registro de varargs também requer o Protocol 3 do VEF — servidores mais antigos rejeitam a extensão no momento da instalação. Isso corresponde ao SDK C++, onde o framework também não pode validar a contagem ou os tipos de argumento para VDFs com varargs.
Seis formas — três formatos, cada um com uma forma abreviada e uma forma completa que adiciona buffer_size e deterministic juntos (nunca isoladamente):
A forma básica não tem validação e aceita uma chamada com zero argumentos — uma escolha legítima para uma função que é total sobre toda entrada, mas isso significa que a função de linha sozinha é responsável por toda entrada que pode receber. Apenas a forma com state: aloca e descarta o estado por instrução; a forma apenas com prerun usa PrerunResult<()> e não armazena nada, então não há postrun para ela — uma prerun dessas usa PrerunResult apenas para error e request_buffer_size, nunca para set_state.

Inspecionando tipos de argumento em uma prerun

Como o servidor não valida nada, uma prerun de varargs precisa ver os tipos dos argumentos antes que a primeira linha seja executada. PrerunArgs::type_at fornece essa visão, junto com len()/is_empty() e os métodos de PrerunResult descritos em Estado por instrução. Combine is_custom() com custom_name() para aceitar exatamente um tipo personalizado: is_custom() sozinho aceita todo tipo personalizado no servidor.
varargs_func! e PrerunArgs::type_at ainda não estão em uma versão publicada. A versão atual do crates.io (0.0.1) não os expõe.
O exemplo vsql_varargs no repositório do SDK declara uma função por forma. Uma função varargs com estado, validada na prerun e carregando um contador de chamadas por instrução:
str_join ainda faz a correspondência de InValue na função de linha mesmo que a prerun tenha provado que todo argumento é uma string: a prerun vê tipos declarados, não valores, e uma coluna STRING pode carregar NULL em qualquer linha.
O exemplo também declara describe (uma função apenas com prerun que rejeita zero argumentos e argumentos não escalares e, em seguida, formata uma lista heterogênea de argumentos) e point_path (que valida com is_custom() e custom_name()). Consulte examples/vsql_varargs/src/lib.rs no repositório do SDK Rust.

macro custom_type!

custom_type! registra um novo tipo de coluna. type_name, persisted_length, max_decode_buffer_length, encode, decode e compare são obrigatórios. hash e default são opcionais, mas recomendados.
O campo default não é um valor padrão de coluna — é uma sondagem de inicialização. O servidor chama encode(default) ao carregar a extensão para verificar se o callback funciona. Se encode retornar Err para o padrão, a extensão falha ao carregar.

macro custom!

villagesql::custom!("type_name") referencia um tipo personalizado pelo nome em uma declaração func!:
Use-o em qualquer lugar onde um villagesql::Type::* apareceria em uma lista de parâmetros ou posição de tipo de retorno. A string deve corresponder ao type_name declarado no custom_type! correspondente.

campos do manifest.json

Toda extensão precisa de um manifest.json ao lado de seu Cargo.toml:
Regras de validação de name: deve começar com uma letra, terminar com uma letra ou dígito, no máximo 64 caracteres. Um manifesto inválido faz com que INSTALL EXTENSION falhe.