Skip to main content
Esta página é a referência dos construtores de operações de tipo em C++. Para a introdução em nível de tutorial aos tipos personalizados, consulte Tipos Personalizados em C++. Os tipos personalizados exigem três operações que o mecanismo chama internamente: encode (string para binário), decode (binário para string) e compare. O hash é opcional. Implemente-as de acordo com estas assinaturas em C++ (todas disponíveis via <villagesql/vsql.h>):

Tipos de Comprimento Fixo

Registre essas operações usando vsql::make_type<kTypeName>(). O nome do tipo é passado como um parâmetro de template que não é de tipo (NTTP) — um array static constexpr const char[]. O construtor gera automaticamente nomes de VDF no formato TYPE::method (por exemplo, "MYTYPE::from_string") a partir desse NTTP, de modo que nenhuma correspondência manual de strings seja necessária. Passe o objeto de tipo construído para .type() no construtor da extensão; chamadas .func() separadas para operações de tipo não são necessárias.
O nome do tipo deve ser uma variável static constexpr const char[] — um literal de string não pode ser usado como parâmetro de template que não é de tipo. Passar "MYTYPE" diretamente produz um erro de compilação como:
Declare o nome como um array nomeado, como mostrado abaixo.
build() falha em tempo de compilação se from_string, to_string ou compare estiver ausente. Cada método de template verifica a assinatura do pointer de função via static_assert.

Padrão Intrínseco

Quando uma coluna de tipo personalizado NOT NULL recebe NULL no modo IGNORE (por exemplo, INSERT IGNORE ou UPDATE IGNORE), o servidor chama o padrão intrínseco para produzir um valor alternativo em vez de gerar um erro. O padrão intrínseco fornece uma representação em string; o servidor a converte para binário usando a função from_string do tipo.
Se você omitir tanto .intrinsic_default_str() quanto .intrinsic_default_vdf(), o servidor chama from_string("") como alternativa. Isso acontece quando o tipo é usado pela primeira vez (na criação da tabela), não em INSTALL EXTENSION. Se a sua função de encode rejeitar a string vazia (ou codificá-la para o número errado de bytes), a inicialização do tipo falha com um erro visível no cliente SQL:
Para tipos de comprimento fixo, a string padrão deve codificar para exatamente persisted_length bytes. Defina um padrão explícito para qualquer tipo em que a string vazia não seja uma entrada válida.
Literal de string: .intrinsic_default_str() Para um padrão constante, passe a string diretamente no construtor do tipo (como mostrado no exemplo de comprimento fixo acima, com .intrinsic_default_str("0")). Baseado em VDF: .intrinsic_default_vdf() + make_intrinsic_default Quando o valor padrão depende dos parâmetros do tipo, implemente uma função de acordo com uma destas assinaturas (disponíveis via <villagesql/vsql.h>):
Mudança incompatível: IntrinsicDefaultFunc e IntrinsicDefaultWithParamsFunc retornam std::string em vez de const char*. Atualize quaisquer implementações de padrão intrínseco existentes para retornar std::string diretamente.
Retorne uma representação std::string do valor padrão. Em caso de erro, escreva uma mensagem em error_msg e retorne qualquer valor (o SDK verifica error_msg[0] != '\0' para detectar erros). Registre com make_intrinsic_default<&fn>("vdf_name") (um argumento: o nome da VDF) e referencie esse nome no construtor do tipo com .intrinsic_default_vdf(). O exemplo de tipos parametrizados abaixo mostra o padrão de registro completo.

Tipos Parametrizados

Os tipos parametrizados precisam dos parâmetros declarados da coluna nos momentos de encode, decode, compare e hash para determinar os tamanhos de alocação e o layout. Defina uma struct de parâmetros com uma função de parse e uma função inversa to_strings, registre ambas no construtor do tipo com .params<P, &ParseFunc, &ToStringsFunc>(), e use const P& como o primeiro argumento das suas funções de operação de tipo. O SDK armazena em cache o resultado do parse por combinação única de parâmetros, de modo que a função de parse é executada no máximo uma vez por instanciação de tipo. A função to_strings é a inversa de parse: ela escreve um P tipado de volta na forma canônica de string chave/valor para que o servidor possa publicar os parâmetros inferidos no mesmo formato que parse consome.
Registre .params<>() no construtor do tipo. Use .int_to_params<&mytype_int_to_params_fn>() para tratar a sintaxe de inteiro MYTYPE(N) e .resolve_params<&mytype_resolve_params_fn>() para validar os parâmetros e calcular os tamanhos de armazenamento. Chame .max_persisted_length(N) com um limite superior do tamanho persistido em bytes em todas as parametrizações válidas; o servidor usa isso apenas no caminho de inferência de parâmetros de tipo, onde ele ainda não inferiu os parâmetros e, portanto, não pode consultar resolve_params para dimensionar o buffer de encode. Para um padrão intrínseco baseado em VDF, use .intrinsic_default_vdf() com o nome da VDF e registre a VDF separadamente via make_intrinsic_default<&mytype_default>().
.max_persisted_length() requer o VEF Protocol 3 ou superior. Um tipo que o utiliza não pode ser carregado por servidores anteriores ao Protocol 3.
As variantes parametrizadas (TypeEncodeWithParamsFunc<P>, TypeDecodeWithParamsFunc<P>, TypeCompareWithParamsFunc<P> e TypeHashWithParamsFunc<P>) juntamente com ParamsToStringsFunc<P> (void fn(const P&, std::map<std::string,std::string>&)) estão disponíveis via <villagesql/vsql.h>. Os métodos de template vsql::make_type detectam o argumento de parâmetros e roteiam através do cache de parâmetros automaticamente. As funções de encode recebem vsql::MaybeParams<P> & como primeiro argumento; is_known() é sempre verdadeiro em tempo de execução, e value() retorna const P&. As variantes de decode, compare e hash recebem vsql::CustomArgWith<P>, cujo acessador params() retorna const P&. Fornecendo parâmetros em SQL. Duas sintaxes chegam a resolve_params:
  • InteiroMYTYPE(N). O servidor roteia N através de int_to_params para construir o mapa de parâmetros. Requer .int_to_params<>().
  • StringMYTYPE('key=value,...'). O servidor normaliza a string e chama resolve_params diretamente; int_to_params não é envolvido. Disponível sempre que .resolve_params<>() estiver registrado — sem chamada extra do construtor.
Um tipo que registra apenas .resolve_params<>() aceita a forma de string e rejeita MYTYPE(N). SHOW CREATE TABLE preserva qualquer forma que tenha sido escrita.
A string de parâmetros serializada key=value,... que int_to_params produz e resolve_params consome é limitada a VEF_MAX_TYPE_PARAMS_STRING_LEN (1024 bytes). Uma parametrização cuja string canônica exceda esse limite é rejeitada com um erro definido em vez de ser truncada silenciosamente — mantenha os nomes e valores de parâmetros combinados de um único tipo dentro de 1024 bytes.

Reescrevendo parâmetros e fornecendo padrões

resolve_params tem uma segunda sobrecarga, mutável: ela recebe o mapa de parâmetros por referência não constante, de modo que o tipo pode reescrevê-lo — normalmente para preencher padrões que o autor omitiu. Registre-a da mesma forma (.resolve_params<&fn>() aceita qualquer forma; registre apenas uma):
O mapa reescrito torna-se a string de parâmetros canônica que o servidor persiste e SHOW CREATE TABLE imprime, portanto a reescrita deve ser idempotente. Uma declaração simples (MYTYPE, sem comprimento ou parâmetros) agora chama resolve_params com um mapa vazio em vez de ignorá-la, de modo que um tipo que fornece padrões dá a cada coluna parâmetros explícitos — o BITFIELD de vsql_bitfield_test resolve uma coluna simples para max_number_of_bits=4096:

Tipos de Comprimento Variável

Um tipo personalizado de comprimento variável decide seu tamanho persistido por valor, em vez de usar um único footprint fixo. Declare um chamando .variable_length_type() no construtor do tipo, o que define a flag variable_length do tipo.
.variable_length_type() eleva o protocol exigido pelo tipo para o VEF Protocol 4. O servidor lê a flag variable_length apenas no protocol 4 ou superior. Compile com os cabeçalhos opcionais da dev ABI (-DVSQL_USE_DEV_ABI=ON); servidores mais antigos não leem a flag.
Os tipos de comprimento variável também devem chamar .max_persisted_length(N). build() falha em tempo de compilação se ele for omitido — o servidor precisa do limite superior para alocar um buffer para o campo de suporte. .variable_length_type() é monotônico: chamá-lo antes ou depois dos setters do Protocol 3 (max_persisted_length(), params(), int_to_params()) não reduz a exigência de protocol de volta para abaixo do Protocol 4.
Como todo tipo personalizado, um tipo de comprimento variável deve produzir um padrão intrínseco utilizável. O padrão é codificado dentro da capacidade máxima do campo, e qualquer resultado não vazio de 1 a max_persisted_length bytes é aceito. Um tipo cujo encode de string vazia produz zero bytes (um array ou conjunto de bits vazio, digamos) não tem um padrão utilizável, portanto declare um explícito que codifique para um valor não vazio:
Caso contrário, o tipo falha ao inicializar na primeira vez que uma coluna NOT NULL o referencia, em CREATE TABLE — o mesmo que um tipo de comprimento fixo que não consegue codificar from_string("").

Tipos Personalizados em Stored Procedures

Tipos personalizados de extensão podem ser usados como tipos de parâmetro de stored procedure e em declarações de variáveis DECLARE. O servidor resolve o tipo personalizado no momento da execução da rotina usando os metadados de tipo da extensão instalada.

Veja Também