Compartilhar via


Funções definidas pelo usuário

A maioria dos bancos de dados tem um dialeto processual do SQL que você pode usar para definir suas próprias funções. No entanto, o SQLite é executado em processo com seu aplicativo. Em vez de ter que aprender um novo dialeto do SQL, basta usar a linguagem de programação do seu aplicativo.

Funções escalares

As funções escalares retornam um único valor escalar para cada linha em uma consulta. Defina novas funções escalares e substitua as internas usando CreateFunction.

Consulte os tipos de dados para obter parâmetros com suporte e tipos de retorno para o argumento func.

Especificar o argumento state passará esse valor para cada invocação da função. Use isso para evitar fechamentos.

Especifique isDeterministic se sua função for determinística para permitir que o SQLite use otimizações adicionais ao compilar consultas.

O exemplo a seguir mostra como adicionar uma função escalar para calcular o raio de um cilindro.

connection.CreateFunction(
    "volume",
    (double radius, double height)
        => Math.PI * Math.Pow(radius, 2) * height);

var command = connection.CreateCommand();
command.CommandText =
@"
    SELECT name,
           volume(radius, height) AS volume
    FROM cylinder
    ORDER BY volume DESC
";

Operadores

Os seguintes operadores SQLite são implementados por funções escalares correspondentes. Definir essas funções escalares em seu aplicativo substituirá o comportamento desses operadores.

Operador Função
X GLOB Y glob(Y, X)
X LIKE Y like(Y, X)
X LIKE Y ESCAPE Z like(Y, X, Z)
X MATCH Y match(Y, X)
X REGEXP Y regexp(Y, X)

O exemplo a seguir mostra como definir a função regexp para habilitar seu operador correspondente. O SQLite não inclui uma implementação padrão da função regexp.

connection.CreateFunction(
    "regexp",
    (string pattern, string input)
        => Regex.IsMatch(input, pattern));

var command = connection.CreateCommand();
command.CommandText =
@"
    SELECT count()
    FROM user
    WHERE bio REGEXP '\w\. {2,}\w'
";
var count = command.ExecuteScalar();

Funções de agregação

As funções de agregação retornam um único valor agregado para todas as linhas em uma consulta. Definir e substituir funções de agregação usando CreateAggregate.

O argumento seed especifica o estado inicial do contexto. Use isso também para evitar fechamentos.

O argumento func é invocado uma vez por linha. Use o contexto para acumular um resultado final. Retorne o contexto. Esse padrão permite que o contexto seja um tipo de valor ou imutável.

Se não for especificado resultSelector, o estado final do contexto será usado como resultado. Isso pode simplificar a definição de funções como soma e contagem que só precisam incrementar um número em cada linha e devolvê-lo.

Especifique resultSelector para calcular o resultado final a partir do contexto depois de iterar em todas as linhas.

Consulte os Tipos de dados para obter uma lista de parâmetros com suporte para o argumento func e tipos de retorno para resultSelector.

Especifique isDeterministic se sua função for determinística para permitir que o SQLite use otimizações adicionais ao compilar consultas.

O exemplo a seguir define uma função de agregação para calcular o desvio padrão de uma coluna.

connection.CreateAggregate(
    "stdev",

    // A tuple to maintain context between rows
    (Count: 0, Sum: 0.0, SumOfSquares: 0.0),

    // This is called for each row
    ((int Count, double Sum, double SumOfSquares) context, double value) =>
    {
        context.Count++;
        context.Sum += value;
        context.SumOfSquares += value * value;

        return context;
    },

    // This is called to get the final result
    context =>
    {
        var variance = context.SumOfSquares - context.Sum * context.Sum / context.Count;

        return Math.Sqrt(variance / context.Count);
    });

var command = connection.CreateCommand();
command.CommandText =
@"
    SELECT stdev(gpa)
    FROM student
";
var stdDev = command.ExecuteScalar();

Errors

Se uma função definida pelo usuário gerar uma exceção, a mensagem será retornada ao SQLite. O SQLite gerará um erro e o Microsoft.Data.Sqlite lançará uma SqliteException. Para obter mais informações, consulte Erros de banco de dados.

Por padrão, o código do erro SQLite será SQLITE_ERROR (ou 1). No entanto, você pode alterá-lo lançando uma função SqliteException com o SqliteErrorCode desejado especificado.

Depuração

O SQLite chama sua implementação diretamente. Isso permite adicionar pontos de interrupção que disparam enquanto o SQLite está avaliando consultas. A experiência completa de depuração do .NET está disponível para ajudá-lo a criar suas funções definidas pelo usuário.

Confira também