Pular para o conteúdo principal
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. Um aviso não faz a instrução falhar, inclusive INSERT e UPDATE no modo estrito. 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.
Retorne um VdfReturn para cada falha, e não cause um panic. O SDK não captura um panic em uma função, agregação, prerun ou postrun, nem nas operações de um tipo personalizado, então um panic que chega ao ponto de entrada extern "C" do SDK aborta o processo do servidor. Isso inclui .unwrap() e .expect() em um None ou em um Err, e a indexação de slice fora dos limites.

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. Oito formas — quatro sem estado por instrução (sem parâmetros, apenas buffer_size, apenas deterministic, ambos), duas que anexam estado por instrução por meio de uma função prerun e mais duas que adicionam uma postrun: opcional sobre essas. Consulte Estado por instrução abaixo.
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! sempre gera a postrun que o descarta quando a instrução termina, então liberá-lo não é responsabilidade sua, mesmo quando você fornece a sua própria finalização. Essa etapa de descarte é o oposto do SDK C++, onde sua postrun tem que chamar delete_state<T>() — consulte Estado por Instrução. Nomeie uma postrun: postrun_fn, fn(&mut StateType), para executar primeiro a sua própria finalização: ela é executada uma vez após a última linha, enquanto o estado ainda pode ser tomado emprestado, e antes do descarte feito pelo próprio SDK. Consulte examples/vsql_postrun_order/src/lib.rs no repositório do SDK Rust, cuja saída de teste registrada inclui a linha prerun,postrun,drop|rows_seen=3, confirmando a ordem. 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:
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.
Oito formas — três formatos, cada um com uma forma abreviada e uma forma completa que adiciona buffer_size e deterministic juntos (nunca isoladamente). O formato state:/ prerun: tem mais duas sobre essas, adicionando uma postrun: opcional — mesmo significado que em func!:
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. 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 é opcional, mas recomendado. Forneça default ou intrinsic_default_fn, não ambos.
O campo default não é um valor padrão de coluna; uma coluna omitida é NULL. Ele fornece a string que o servidor codifica ao inicializar o tipo, e isso acontece na primeira vez em que uma instrução nomeia o tipo, e não quando a extensão é instalada. Se você não fornecer nem default nem intrinsic_default_fn, o servidor codifica a string vazia. Em qualquer caso, um encode que retorna Err faz essa instrução falhar e deixa o tipo inutilizável:
Fornecer tanto default quanto intrinsic_default_fn é recusado quando a extensão é instalada, e não adiado para o primeiro uso.

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.