Visão geral
O framework de extensões do VillageSQL (VEF) permite adicionar funcionalidades personalizadas ao servidor de banco de dados. Este guia percorre a criação de uma extensão em C++ usando o SDK C++ e o template de extensão. Para escrever implementações de VDF em profundidade (como tipos de argumento e de retorno, agregados, variáveis de sistema e tipos parametrizados), consulte o Guia de Desenvolvimento.Se você prefere Rust, consulte Criando Extensões em Rust.
O que é uma Extensão do VillageSQL?
Uma extensão do VillageSQL é empacotada como um arquivo VEB (VillageSQL Extension Bundle) contendo:- Manifesto - Metadados sobre a extensão (nome, versão, descrição)
- Biblioteca compartilhada - Código C++ compilado que implementa a funcionalidade
- Metadados opcionais - Recursos ou configurações adicionais
- API C++ para definir tipos e funções
- Registro automático sem scripts SQL
- Tipos de argumento e de retorno com segurança de tipos
- Padrão de builder para a definição da extensão
VDFs vs UDFs tradicionais: Funções registradas por meio do VEF são chamadas de VDFs (VillageSQL Defined Functions). O VillageSQL também oferece suporte a UDFs tradicionais do MySQL registradas via
CREATE FUNCTION ... SONAME, mas VDFs são recomendadas para novas extensões.Chamando VDFs em SQL
VDFs podem ser chamadas com ou sem o prefixo da extensão:- Funções de sistema (funções nativas do MySQL como
NOW(),CONCAT()) - UDFs (funções tradicionais definidas pelo usuário do MySQL)
- VDFs (funções de extensão) - apenas se houver exatamente uma função com esse nome
- Funções armazenadas (criadas com
CREATE FUNCTION)
- Use
extension.function_namequando várias extensões fornecem funções com o mesmo nome - Use nomes não qualificados para um código mais limpo quando não houver ambiguidade
- A qualificação nunca é obrigatória se apenas uma extensão fornecer aquele nome de função
- Funções personalizadas (VDFs) - Funções SQL com verificação e validação de tipos automáticas
- Tipos de dados personalizados - Novos tipos de coluna como COMPLEX, UUID ou VECTOR que funcionam com ORDER BY e índices
- Operações de tipo - Funções de encode, decode, compare e hash para tipos personalizados
Pré-requisitos
Antes de começar, compile o VillageSQL a partir do código-fonte — extensões são vinculadas aos cabeçalhos do SDK e à árvore de compilação do servidor. Siga primeiro o guia Compilar a Partir do Código-Fonte. Você também precisa de:- Git - Para clonagem e controle de versão
- CMake 3.18 ou superior - Sistema de compilação
- Compilador C++ - GCC 8+, Clang 8+ ou MSVC 2019+ com suporte a C++17
- Conhecimento básico de C++ - Compreensão de C++ e pointers de função
Passo 1: Obtenha o Template de Extensão
Você pode começar com o template de extensão de duas maneiras:Opção A: Usar o Template a Partir do Código-Fonte do VillageSQL
Se você tem o código-fonte do VillageSQL, o template já está incluído:Opção B: Fazer um Fork no GitHub
Comece fazendo um fork do repositório do template de extensão do VillageSQL:-
Acesse o repositório do template no GitHub:
- Clique no botão “Fork” para criar sua própria cópia
-
Clone seu fork localmente:
Passo 2: Atualize o Manifesto
Editemanifest.json para definir os metadados da sua extensão:
$schema é opcional, mas habilita o autocompletar da IDE e a validação inline
para todos os campos do manifesto.
Esquema do manifest.json
Regras de validação:
name: Deve começar com uma letra e terminar com uma letra ou dígito. Pode conter letras minúsculas, dígitos, sublinhados e hifens. Máximo de 64 caracteres. Use sublinhados — hifens exigem uso de crases (backticks) em SQL.version: Deve seguir o versionamento semântico (ex.: 1.0.0, 0.2.1)- Um manifesto inválido fará com que
INSTALL EXTENSIONfalhe
Passo 3: Implemente Sua Extensão com o SDK C++
O SDK C++ fornece uma API C++ para definir extensões usando um padrão de builder fluente:- Definições de função com segurança de tipos e verificação em tempo de compilação
- Validação automática de argumentos e conversão de tipos
- Suporte a tipos personalizados com funções compare/hash (habilita ORDER BY e índices)
Inclua os Cabeçalhos do VillageSQL
Crie o arquivo principal da sua extensão (ex.:src/extension.cc) e inclua os cabeçalhos do SDK C++:
<villagesql/vsql.h> traz o builder de tipos, o builder de funções e
o builder de extensão, e reexporta símbolos comumente usados para o namespace vsql.
Defina Sua Extensão
Use a macroVEF_GENERATE_ENTRY_POINTS() para definir sua extensão:
make_func<&impl>("name")- Cria a função com o pointer de implementação.returns(type)- Define o tipo de retorno (STRING, INT, REAL ou nome de tipo personalizado).param(type)- Adiciona um parâmetro (máximo de 8 parâmetros).buffer_size(size_t)- Solicita um tamanho de buffer de saída específico para retornos STRING/CUSTOM.max_result_length(size_t)- Dimensiona a coluna de resultado para um retorno STRING para que um resultado materializado não seja truncado na largura do argumento. Valores acima deVEF_MAX_RESULT_LENGTH(16 MiB) são limitados pelo servidor. Somente STRING; chame.returns(STRING)primeiro. Requer o Protocol 4 (dev ABI)..deterministic(bool = true)- Declara que esta função sempre retorna a mesma saída para as mesmas entradas e não tem efeitos colaterais. O padrão é não determinístico..prerun<func>()- Define a função de preparação por instrução (opcional).postrun<func>()- Define a função de limpeza por instrução (opcional).build()- Finaliza o registro da função
Limite de Parâmetros: As funções oferecem suporte a no máximo 8 parâmetros (definido por
kMaxParams). Se você precisar de mais, considere usar tipos estruturados ou várias funções.VDFs com Argumentos e Valores de Retorno de Tipo Personalizado
Uma VDF pode receber e retornar valores de tipo personalizado usando.param(TYPE_NAME) e
.returns(TYPE_NAME) no builder. A implementação usa CustomArg
para entrada e CustomResult para saída — os mesmos tipos de argumento e resultado usados nas operações
de tipo:
.param(COMPLEX) e .returns(COMPLEX):
CustomArg/CustomResult, incluindo CustomArgWith<P>
e CustomResultWith<P> para tipos parametrizados.
Funções Determinísticas
Por padrão, VDFs são registradas como não determinísticas. Uma função não determinística é bloqueada em três contextos SQL: colunas geradas, restrições CHECK e valores padrão de expressão (DEFAULT (expr) em uma coluna) — usar qualquer um desses recursos com uma VDF não determinística retorna um erro. Se sua função sempre produz a mesma saída para as mesmas entradas e não tem efeitos colaterais, você pode declará-la determinística adicionando .deterministic() à cadeia do builder.
O otimizador pode usar essa informação para avaliar a função uma vez por instrução e reutilizar o valor entre as linhas, em vez de chamá-la por linha. Marcar incorretamente uma função não determinística como determinística pode, portanto, fazer com que o servidor retorne o mesmo resultado para entradas que deveriam produzir saídas diferentes. Adicione .deterministic() apenas quando sua função realmente não tiver dependência de estado externo, aleatoriedade ou tempo.
Assinatura do builder: .deterministic(bool d = true) — a forma sem argumentos assume true como padrão.
Exemplo:
complex_add é declarada determinística, ela pode ser usada em uma definição de coluna gerada:
Tamanhos de Buffer Personalizados
Para funções que retornam dados de comprimento variável, solicite um tamanho de buffer específico:buffer() e set_length(), o buffer
tem tamanho fixo de buffer().size() bytes — escrever além dele causa estouro de memória, então proteja-se
contra isso:
out.set(sv) segue um contrato de estouro no estilo snprintf: ele
copia quantos bytes couberem e informa o tamanho total do valor via set_length.
Quando o tamanho informado excede o buffer, o servidor aumenta o buffer de resultado e
reinvoca a função, de modo que um valor STRING maior que o buffer solicitado deixa de ser truncado.
Esse contrato se aplica no momento da linha. Um resultado STRING materializado (em uma
tabela temporária de GROUP BY/DISTINCT, CREATE TABLE ... SELECT ou UNION) ainda
é truncado na largura do argumento, a menos que a função declare
.max_result_length(n), que dimensiona a coluna de resultado (em caracteres, limitada a
VEF_MAX_RESULT_LENGTH, 16 MiB):
Solicite um tamanho de buffer suficiente via
.buffer_size() com base no tamanho máximo de saída da sua função. Dimensionar o buffer corretamente evita o custo de um ciclo de aumento-e-nova-tentativa.Antes de implementar suas funções, revise a Referência da API C++ para os contratos completos de VDF: verificação de null, tipos de resultado, dimensionamento de buffer e tratamento de erros.
Passo 4: Criando Tipos Personalizados
Tipos personalizados permitem definir novos tipos de coluna — comoCOMPLEX, UUID ou
VECTOR — que funcionam com ORDER BY, índices e funções de agregação.
Se sua extensão registra apenas funções, pule para o Passo 5.
Consulte Tipos Personalizados em C++ para o passo a passo completo
da implementação. Se seu tipo recebe parâmetros (ex.: VECTOR(1536)),
consulte Tipos Parametrizados.
Passo 5: Atualize a Configuração de Compilação
EditeCMakeLists.txt para compilar sua extensão como um arquivo VEB:
VillageSQLExtensionFrameworkfornece helpers do CMake para compilar extensõesVEF_CREATE_VEB()empacota sua biblioteca, manifesto e metadados em um arquivo.veb- O framework detecta automaticamente as flags de compilação do MySQL/VillageSQL
- O nome do target da biblioteca é normalmente
extension(pode ser qualquer um) - O nome do VEB deve corresponder ao nome no seu manifest.json
- Por padrão, extensões são compiladas com os cabeçalhos da ABI estável. Defina
-DVSQL_USE_DEV_ABI=ONpara compilar com os cabeçalhos instáveis da dev ABI
Passo 6: Crie um Diretório de Compilação
Crie um diretório de compilação separado:Passo 7: Compile com CMake e Make
Configure e compile sua extensão:- Biblioteca compartilhada compilada (arquivo
.so) - Pacote VEB (arquivo
.veb) - um arquivo tar contendo manifesto e biblioteca
Verifique a Compilação
Verifique o conteúdo do seu arquivo VEB:Passo 8: Instale e Teste
Opção A: Instalar no Diretório de Extensões do VillageSQL
Use o target de instalação para copiar o VEB para sua instalação do VillageSQL:.veb para o diretório configurado via VillageSQL_VEB_INSTALL_DIR.
Opção B: Instalação Manual
Copie o arquivo VEB manualmente:Teste Sua Extensão
-
Conecte-se ao VillageSQL:
-
Instale a extensão:
-
Verifique a instalação:
-
Teste suas funções:
Criando Testes
Adicione arquivos de teste para validar que sua extensão funciona corretamente:-
Crie um arquivo de teste em
mysql-test/t/: -
Gere os resultados esperados:
-
Execute os testes:
Solução de Problemas
A Extensão Não Carrega
Verifique o log de erros e confira o conteúdo do VEB:Função Não Encontrada
Verifique a instalação e o registro:Erros de Compilação
Extensões de Exemplo
Aprenda com extensões existentes do VillageSQL:vsql_complex
Implementação do tipo de dado de número complexo
vsql_extension_template
Template mínimo para criar extensões
Próximos Passos
Instalando Extensões
Aprenda a instalar e gerenciar extensões
Guia de Desenvolvimento
Tipos de argumento e de retorno, agregados, variáveis de sistema e testes
Arquitetura de Extensões
Ciclo de vida, cache, desempenho e modelo de segurança
Compilar a Partir do Código-Fonte
Compile o VillageSQL a partir do código-fonte

