Partilhar via


Tutorial: Pesquisar uma cadeia de caracteres usando expressões regulares (regex) em Java

Aplica-se a: SQL Server 2019 (15.x) e versões posteriores

Este tutorial mostra como usar as Extensões de Linguagem do SQL Server para criar uma classe Java que recebe duas colunas (ID e texto) do SQL Server e uma expressão regular (regex) como um parâmetro de entrada. A classe retorna duas colunas de volta para o SQL Server (ID e texto).

Para um determinado texto na coluna de texto enviada para a classe Java, o código verifica se a expressão regular dada foi cumprida e retorna esse texto junto com o ID original.

Este código de exemplo usa uma expressão regular que verifica se um texto contém a palavra Java ou java.

Pré-requisitos

A compilação de linha de comando usando javac é suficiente para este tutorial.

Criar dados de exemplo

Primeiro, crie um novo banco de dados e preencha uma testdata tabela com ID e text colunas.

CREATE DATABASE javatest;
GO

USE javatest;
GO

CREATE TABLE testdata
(
    [id] INT NOT NULL,
    [text] NVARCHAR (100) NOT NULL
);
GO

-- Insert data into test table
INSERT INTO testdata ([id], [text]) VALUES (1, 'This sentence contains java');
INSERT INTO testdata ([id], [text]) VALUES (2, 'This sentence does not');
INSERT INTO testdata ([id], [text]) VALUES (3, 'I love Java!');
GO

Criar a classe principal

Nesta etapa, crie um arquivo de classe chamado RegexSample.java e copie o seguinte código Java para esse arquivo.

Essa classe principal está importando o SDK, o que significa que o arquivo jar baixado na etapa 1 precisa ser detetável a partir dessa classe.

package pkg;

import com.microsoft.sqlserver.javalangextension.PrimitiveDataset;
import com.microsoft.sqlserver.javalangextension.AbstractSqlServerExtensionExecutor;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.regex.*;

public class RegexSample extends AbstractSqlServerExtensionExecutor {
    private Pattern expr;

    public RegexSample() {
        // Setup the expected extension version, and class to use for input and output dataset
        executorExtensionVersion = SQLSERVER_JAVA_LANG_EXTENSION_V1;
        executorInputDatasetClassName = PrimitiveDataset.class.getName();
        executorOutputDatasetClassName = PrimitiveDataset.class.getName();
    }

    public PrimitiveDataset execute(PrimitiveDataset input, LinkedHashMap<String, Object> params) {
        // Validate the input parameters and input column schema
        validateInput(input, params);

        int[] inIds = input.getIntColumn(0);
        String[] inValues = input.getStringColumn(1);
        int rowCount = inValues.length;

        String regexExpr = (String)params.get("regexExpr");
        expr = Pattern.compile(regexExpr);

        System.out.println("regex expression: " + regexExpr);

        // Lists to store the output data
        LinkedList<Integer> outIds = new LinkedList<Integer>();
        LinkedList<String> outValues = new LinkedList<String>();

        // Evaluate each row
        for(int i = 0; i < rowCount; i++) {
            if (check(inValues[i])) {
                outIds.add(inIds[i]);
                outValues.add(inValues[i]);
            }
        }

        int outputRowCount = outValues.size();

        int[] idOutputCol = new int[outputRowCount];
        String[] valueOutputCol = new String[outputRowCount];

        // Convert the list of output columns to arrays
        outValues.toArray(valueOutputCol);

        ListIterator<Integer> it = outIds.listIterator(0);
        int rowId = 0;

        System.out.println("Output data:");
        while (it.hasNext()) {
            idOutputCol[rowId] = it.next().intValue();

            System.out.println("ID: " + idOutputCol[rowId] + " Value: " + valueOutputCol[rowId]);
            rowId++;
        }

        // Construct the output dataset
        PrimitiveDataset output = new PrimitiveDataset();

        output.addColumnMetadata(0, "ID", java.sql.Types.INTEGER, 0, 0);
        output.addColumnMetadata(1, "Text", java.sql.Types.NVARCHAR, 0, 0);

        output.addIntColumn(0, idOutputCol, null);
        output.addStringColumn(1, valueOutputCol);

        return output;
    }

    private void validateInput(PrimitiveDataset input, LinkedHashMap<String, Object> params) {
        // Check for the regex expression input parameter
        if (params.get("regexExpr") == null) {
            throw new IllegalArgumentException("Input parameter 'regexExpr' is not found");
        }

        // The expected input schema should be at least 2 columns, (INTEGER, STRING)
        if (input.getColumnCount() < 2) {
            throw new IllegalArgumentException("Unexpected input schema, schema should be an (INTEGER, NVARCHAR or VARCHAR)");
        }

        // Check that the input column types are expected
        if (input.getColumnType(0) != java.sql.Types.INTEGER &&
                (input.getColumnType(1) != java.sql.Types.VARCHAR && input.getColumnType(1) == java.sql.Types.NVARCHAR )) {
            throw new IllegalArgumentException("Unexpected input schema, schema should be an (INTEGER, NVARCHAR or VARCHAR)");
        }
    }

    private boolean check(String text) {
        Matcher m = expr.matcher(text);

        return m.find();
    }
}

Compilar e criar um arquivo .jar

Empacote suas classes e dependências em um .jar arquivo. A maioria dos IDEs Java (por exemplo, Eclipse ou IntelliJ) suporta a geração .jar de arquivos quando você constrói ou compila o projeto. Nomeie o .jar arquivo regex.jar.

Se você não estiver usando um IDE Java, poderá criar manualmente um .jar arquivo. Para obter mais informações, consulte Criar um arquivo Java .jar a partir de arquivos de classe.

Observação

Este tutorial usa pacotes. A package pkg; linha na parte superior da classe garante que o código compilado seja salvo em uma subpasta chamada pkg. Se você usar um IDE, o código compilado será salvo automaticamente nessa pasta. Se você usar javac para compilar manualmente as classes, você precisa colocar o código compilado pkg na pasta.

Criar idioma externo

Você precisa criar um idioma externo no banco de dados. A linguagem externa é um objeto com escopo de banco de dados, o que significa que linguagens externas como Java precisam ser criadas para cada banco de dados em que você deseja usá-lo.

Criar idioma externo no Windows

Se estiver a utilizar o Windows, siga estes passos para criar uma linguagem externa para Java.

  1. Crie um arquivo .zip contendo a extensão.

    Como parte da instalação do SQL Server no Windows, o arquivo de extensão .zip Java é instalado neste local: [SQL Server install path]\MSSQL\Binn\java-lang-extension.zip. Este ficheiro zip contém o javaextension.dllficheiro .

  2. Crie uma linguagem externa Java a partir do arquivo .zip:

    CREATE EXTERNAL LANGUAGE Java
    FROM
    (CONTENT = N'[SQL Server install path]\MSSQL\Binn\java-lang-extension.zip', FILE_NAME = 'javaextension.dll',
    ENVIRONMENT_VARIABLES = N'{"JRE_HOME":"<path to JRE>"}' );
    GO
    

Criar linguagem externa no Linux

Como parte da instalação, o arquivo de extensão .tar.gz é salvo no seguinte caminho: /opt/mssql-extensibility/lib/java-lang-extension.tar.gz.

Para criar uma linguagem externa Java, execute a seguinte instrução T-SQL no Linux:

CREATE EXTERNAL LANGUAGE Java
FROM (CONTENT = N'/opt/mssql-extensibility/lib/java-lang-extension.tar.gz', file_name = 'javaextension.so',
ENVIRONMENT_VARIABLES = N'{"JRE_HOME":"<path to JRE>"}' );
GO

Permissões para executar linguagem externa

Para executar código Java, um usuário precisa receber execução de script externo nessa linguagem específica.

Para obter mais informações, consulte CREATE EXTERNAL LANGUAGE.

Criar bibliotecas externas

Use CREATE EXTERNAL LIBRARY para criar uma biblioteca externa para seus .jar arquivos. O SQL Server tem acesso aos .jar arquivos e você não precisa definir nenhuma permissão especial para o classpath.

Neste exemplo, você cria duas bibliotecas externas. Um para o SDK e outro para o código RegEx Java.

  1. O arquivo mssql-java-lang-extension.jar jar do SDK é instalado como parte do SQL Server 2019 (15.x) e versões posteriores, no Windows e Linux.

    • Caminho de instalação padrão no Windows: <instance installation home directory>\MSSQL\Binn\mssql-java-lang-extension.jar

    • Caminho de instalação padrão no Linux: /opt/mssql/lib/mssql-java-lang-extension.jar

    O código também é de código aberto e pode ser encontrado no repositório GitHub do SQL Server Language Extensions. Para obter mais informações, consulte Microsoft Extensibility SDK for Java for SQL Server.

  2. Crie uma biblioteca externa para o SDK.

    CREATE EXTERNAL LIBRARY sdk
    FROM (CONTENT = '<OS specific path from above>/mssql-java-lang-extension.jar')
    WITH (LANGUAGE = 'Java');
    GO
    
  3. Crie uma biblioteca externa para o código RegEx.

    CREATE EXTERNAL LIBRARY regex
    FROM (CONTENT = '<path>/regex.jar')
    WITH (LANGUAGE = 'Java');
    GO
    

Definir permissões

Observação

Ignore esta etapa, se você usar bibliotecas externas na etapa anterior. A maneira recomendada é criar uma biblioteca externa a partir do seu .jar arquivo.

Se você não quiser usar bibliotecas externas, precisará definir as permissões necessárias. A execução de scripts só será bem-sucedida se as identidades do processo tiverem acesso ao seu código. Você pode encontrar mais informações sobre como definir permissões no guia de instalação.

No sistema Linux

Conceda permissões de leitura/execução no classpath ao mssql_satellite usuário.

No ambiente Windows

Conceda permissões de 'Leitura e Execução' ao SQLRUserGroup e ao SID Todos os pacotes de aplicativos na pasta que contém o código Java compilado.

Toda a árvore deve ter permissões, desde o pai raiz até a última subpasta.

  1. Clique com o botão direito do mouse na pasta (por exemplo, C:\myJavaCode) e escolha Segurança de propriedades>.
  2. Selecione Editar.
  3. Selecione Adicionar.
  4. Em Selecionar Usuários, Computador, Contas de Serviço ou Grupos:
    1. Selecione Tipos de objeto e verifique se Princípios de segurança internos e Grupos estão selecionados.
    2. Selecione Locais para selecionar o nome do computador local na parte superior da lista.
  5. Digite SQLRUserGroup, verifique o nome e selecione OK para adicionar o grupo.
  6. Digite TODOS OS PACOTES DE APLICATIVOS, verifique o nome e selecione OK para adicionar. Se o nome não resolver, revisite a etapa Locais. O SID é local para a sua máquina.

Verifique se ambas as identidades de segurança têm permissões de Leitura e Execução na pasta e na pkg subpasta.

Chamar a classe Java

Crie um procedimento armazenado que chame sp_execute_external_script o código Java do SQL Server. No parâmetro, defina qual scriptpackage.class você deseja chamar. No código a seguir, a classe pertence a um pacote chamado pkg e um arquivo de classe chamado RegexSample.java.

Observação

O código não está definindo qual método chamar. Por padrão, o execute método será chamado. Isso significa que você precisa seguir a interface do SDK e implementar um método execute em sua classe Java, se quiser ser capaz de chamar a classe do SQL Server.

O procedimento armazenado usa uma consulta de entrada (conjunto de dados de entrada) e uma expressão regular e retorna as linhas que preencheram a expressão regular dada. Ele usa uma expressão [Jj]ava regular que verifica se um texto contém a palavra Java ou java.

CREATE OR ALTER PROCEDURE [dbo].[java_regex] (
    @expr NVARCHAR (200),
    @query NVARCHAR (400)
)
AS
BEGIN
    --Call the Java program by giving the package.className in @script
    --The method invoked in the Java code is always the "execute" method
    EXECUTE sp_execute_external_script
        @language = N'Java',
        @script = N'pkg.RegexSample',
        @input_data_1 = @query,
        @params = N'@regexExpr nvarchar(200)',
        @regexExpr = @expr
        WITH RESULT SETS
    (
            (ID INT, TEXT NVARCHAR (100))
    );
END
GO

--Now execute the above stored procedure and provide the regular expression and an input query
EXECUTE [dbo].[java_regex] N'[Jj]ava', N'SELECT id, text FROM testdata';
GO

Results

Depois de executar a chamada, você deve obter um conjunto de resultados com duas das linhas.

Captura de tela do exemplo Resultados do Java.

Se você receber um erro

  • Quando você compila suas classes, a pkg subpasta deve conter o código compilado para todas as três classes.

  • Se você não estiver usando bibliotecas externas, verifique as root permissões em cada pasta, da subpasta para pkg a subpasta, para garantir que as identidades de segurança que executam o processo externo tenham permissão para ler e executar seu código.