Escrevendo Funções de Extensão
As funções de extensão são escritas em C++ e registradas com o VEF. Inclua um único cabeçalho para acessar o SDK completo:Tipos de Argumento e Resultado
Os parâmetros e resultados de VDF são passados como tipos de argumento e resultado com segurança de tipo. O framework os detecta a partir da assinatura da sua função e se adapta automaticamente — a sintaxe de registromake_func permanece inalterada.
Tipos de argumento: IntArg, RealArg, StringArg, CustomArg — cada um
fornece is_null() e value(). Para tipos personalizados parametrizados,
CustomArgWith<P> adiciona um acessador params() que retorna a struct de params
analisada e armazenada em cache (consulte Tipos Parametrizados).
Tipos de resultado: IntResult, RealResult, StringResult, CustomResult
— cada um fornece set_null(), warning(msg) e error(msg). Os resultados
escalares também fornecem set(value). Os resultados de buffer fornecem buffer() e
set_length(len). StringResult também fornece
set(std::string_view), que copia até buffer().size() bytes da
view e define o comprimento em uma única chamada. Para tipos personalizados parametrizados,
CustomResultWith<P> adiciona um acessador params().
Tipo Span: value() e buffer() nos tipos de argumento e resultado
orientados a bytes retornam um vsql::Span<T> — uma view não proprietária sobre uma sequência
contígua de T com data(), size(), empty(), begin()/end() e
operator[]. No C++20 ele é um alias para std::span<T>; no C++17, este
SDK fornece uma implementação mínima compatível, de modo que o mesmo código compila em
qualquer um dos padrões. Ele está disponível através de <villagesql/vsql.h>.
warning(msg) retorna SQL NULL para a linha e anexa um aviso SQL. No modo estrito (STRICT_TRANS_TABLES), o MySQL o promove a um erro de instrução em INSERT/UPDATE, então ele se comporta como error(msg) em contextos estritos. Use-o para entrada inválida recuperável, como uma string que não pode ser analisada em uma função de codificação. Use error(msg) para dados armazenados corrompidos ou qualquer condição em que continuar seja inseguro. A mensagem de ambos é truncada para caber no buffer de erro interno do servidor, se necessário.
Exemplo escalar — soma dois inteiros:
StringResult e CustomResult, escreva em buffer() e, em seguida, chame
set_length() com o número de bytes escritos. buffer().size() é a
capacidade máxima.
Para VDFs que retornam um tipo personalizado (returns(CUSTOM(MYTYPE))), o servidor
dimensiona o buffer de resultado para o persisted_length do tipo de retorno resolvido
automaticamente — os autores de extensões não precisam declarar .buffer_size(...)
no construtor da função nesse caso. Se prerun aumentar ainda mais o buffer,
esse tamanho maior é preservado. É isso que permite, por exemplo, que
SVECTOR::from_string('[…1024 floats…]') codifique um vetor amplo sem que o
buffer de resultado fique sem espaço.
Você pode usar estilos diferentes entre funções na mesma extensão — o estilo de cada
função é determinado por sua própria assinatura.
VDFs Agregadas
As VDFs agregadas acumulam estado entre linhas dentro de cada grupoGROUP BY e
retornam um único resultado por grupo, como SUM ou COUNT do SQL. Use
make_aggregate_func<State, &result_fn>("name") para registrar uma. O tipo State
é o buffer de acumulação por grupo; prerun e postrun são
gerados automaticamente para alocá-lo e removê-lo.
A função de resultado deve ter a assinatura void(const State&, ResultType)
onde ResultType é um dentre IntResult, RealResult, StringResult,
CustomResult ou CustomResultWith<P>. Chame out.set(value) para retornar um
valor ou out.set_null() para retornar SQL NULL.
Tanto .clear<>() quanto .accumulate<>() são obrigatórios. O construtor impõe
isso em tempo de compilação (via build()), e o servidor valida novamente no
momento do INSTALL EXTENSION — clear redefine o estado, accumulate acumula as linhas e
a função de resultado lê o estado final.
make_aggregate_func<State, &result_fn>()gera automaticamenteprerunepostrun(inicializa por valor e remove oState)..clear<&fn>()registra sua função de redefiniçãovoid(State&)..accumulate<&fn>()registra sua função de acumulaçãovoid(State&, TypedArgs...). OsTypedArgssão deduzidos da assinatura da função (IntArg,StringArg, etc.).- O tipo de resultado (
IntResult,RealResult, etc.) é deduzido da assinatura da função de resultado.
StringResult retorna texto: o resultado informa o
charset e a collation utf8mb4_bin, de modo que os clientes o exibem como caracteres
em vez de hexadecimal — o mesmo que o caminho STRING da VDF escalar. Ela também respeita
.max_result_length(n) da mesma forma, dimensionando um resultado agregado materializado
(uma tabela temporária de GROUP BY/DISTINCT, CREATE TABLE ... SELECT ou UNION) de modo que ele
não seja truncado na largura do argumento. Consulte
Tamanhos de Buffer Personalizados para as
regras de dimensionamento e o limite.
Estado por Instrução (Prerun e Postrun)
Algumas VDFs precisam de estado que abranja cada linha que uma única consulta toca — um contador de chamadas, um resultado em cache, um recurso aberto. Aloque-o em um gancho prerun, acesse-o a partir do corpo da VDF e libere-o em um gancho postrun. Ambos os ganchos são executados uma vez por instrução; o corpo da VDF é executado uma vez por linha. Registre-os com.prerun<&Hook>() e .postrun<&Hook>(). As assinaturas
obrigatórias são:
Use
PrerunResult::set_user_data(void*) para armazenar o estado; use PostrunArgs::delete_state<T>() para liberá-lo. Se prerun chamar set_user_data(new T{}), postrun deve chamar delete_state<T>() — o SDK não libera automaticamente.
PrerunArgs::type_at(i) expõe o tipo SQL declarado de cada argumento antes que qualquer linha seja lida; os predicados is_int(), is_real(), is_str(), is_custom() no PrerunArgType retornado espelham os tipos de coluna. Use isto em prerun para validar os tipos de argumento ou chame PrerunResult::request_buffer_size(n) para dimensionar o buffer de resultado.
VDFs com Varargs
Uma VDF com varargs aceita qualquer número de argumentos de qualquer tipo SQL. Declare uma com.varargs() no construtor da função, o que é mutuamente exclusivo com
.no_params() e .param(TYPE). O corpo recebe um argumento vsql::VarArgs
em vez dos tipos de argumento usuais de aridade fixa.
O framework não pode validar a contagem ou os tipos de argumento para VDFs com varargs. Combine
cada registro de varargs com um gancho prerun que chame PrerunResult::error()
em entrada inválida ou PrerunResult::request_buffer_size(n) para dimensionar o buffer de
resultado.
Itere sobre os argumentos com range-for. Cada elemento AnyArg requer uma verificação de
tipo antes de ler seu valor:
Verifique
is_null() antes de qualquer acessador — todos os quatro são indefinidos em um argumento nulo.
VEF_GENERATE_REGISTRATION
VEF_GENERATE_REGISTRATION cria um auxiliar interno _vef_do_register()
que realiza o registro da extensão, mas não define os pontos de entrada
extern "C". Use-o quando precisar personalizar o comportamento de vef_register — por
exemplo, para corrigir descritores após o registro em uma compilação de teste. Para extensões
normais, use VEF_GENERATE_ENTRY_POINTS em vez disso.
Operações de Tipos Personalizados
Para a referência completa do construtor de operações de tipo — codificação, decodificação, comparação, hash, padrões intrínsecos e tipos parametrizados — consulte Operações de Tipo.Capabilities Preview
As seguintes capabilities do VEF estão disponíveis como cabeçalhos Preview opcionais. A ABI e a API ainda estão em desenvolvimento ativo; consulte Capabilities Preview para a referência completa.- Variáveis de sistema de extensão — Capabilities Preview → Variáveis de Sistema
- Variáveis de status de extensão — Capabilities Preview → Variáveis de Status
- Acesso ao keyring — Capabilities Preview → Acesso ao Keyring
- Armazenamento de coluna — Capabilities Preview → Armazenamento de Coluna
Inspecionando os Metadados de Registro da Extensão
INFORMATION_SCHEMA.EXTENSION_REGISTRATION expõe a struct de registro do VEF
em memória para cada extensão carregada como um documento JSON. Use-o para
verificar se o servidor analisou corretamente as funções, os tipos e as variáveis de sistema
da sua extensão após o INSTALL EXTENSION.
Veja Também
- Criando Extensões em C++ — etapas de compilação de ponta a ponta, configuração do CMake e instalação
- Testes em C++ — servidor de desenvolvimento local, MTR e depuração de falhas
- Operações de Tipo — codificação, decodificação, comparação, hash, tipos parametrizados
- Referência da API C++ — contratos de VDF, tratamento de nulos e dimensionamento de buffer
- Arquitetura de Extensões — ciclo de vida, cache do Victionary, padrões de desempenho e modelo de segurança

