Skip to main content
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.

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.