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 comstate: 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.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.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.
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.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.
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!:
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 ummanifest.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.
