Esercitazione: cercare una stringa usando espressioni regolari (regex) in Java

Si applica a: SQL Server 2019 (15.x) e versioni successive

Questa esercitazione illustra come usare le estensioni del linguaggio di SQL Server per creare una classe Java che riceve due colonne (ID e testo) da SQL Server e un'espressione regolare (regex) come parametro di input. La classe restituisce due colonne (ID e testo) a SQL Server.

Per un determinato testo nella colonna di testo inviata alla classe Java, il codice controlla se l'espressione regolare specificata viene soddisfatta e restituisce tale testo insieme all'ID originale.

Questo codice di esempio usa un'espressione regolare che controlla se un testo contiene la parola Java o java.

Prerequisiti

La compilazione da riga di comando con javac è sufficiente per questa esercitazione.

Creare dati di esempio

Creare prima di tutto un nuovo database e popolare una testdata tabella con ID le colonne e text .

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

Creare la classe principale

In questo passaggio creare un file di classe denominato RegexSample.java e copiare il codice Java seguente in tale file.

Questa classe principale importa l'SDK, il che significa che il file con estensione jar scaricato nel passaggio 1 deve essere individuabile da questa 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();
    }
}

Compilare e creare un file con estensione jar

Assemblare le classi e le dipendenze in un file .jar. La maggior parte degli ambienti IDE Java (ad esempio, Eclipse o IntelliJ) supporta la generazione di file .jar quando si crea o si compila il progetto. Denominare il .jar file regex.jar.

Se non si usa un IDE Java, è possibile creare manualmente un .jar file. Per altre informazioni, vedere Creare un file jar Java da file di classe.

Nota

In questa esercitazione vengono usati i pacchetti. La package pkg; riga all'inizio della classe garantisce che il codice compilato venga salvato in una sottocartella denominata pkg. Se si usa un IDE, il codice compilato viene salvato automaticamente in questa cartella. Se si usa javac per compilare manualmente le classi, è necessario inserire il codice compilato nella pkg cartella .

Creare un linguaggio esterno

È necessario creare un linguaggio esterno nel database. Il linguaggio esterno è un oggetto con ambito di database, il che significa che è necessario creare linguaggi esterni come Java per ogni database in cui si vuole usarlo.

Creare un linguaggio esterno in Windows

Se si usa Windows, seguire questa procedura per creare un linguaggio esterno per Java.

  1. Creare un file ZIP contenente l'estensione.

    Nell'ambito dell'installazione di SQL Server in Windows, il file di estensione .zip Java viene installato in questo percorso: [SQL Server install path]\MSSQL\Binn\java-lang-extension.zip. Questo file ZIP contiene l'oggetto javaextension.dll.

  2. Creare un linguaggio esterno Java dal file 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
    

Creare un linguaggio esterno in Linux

Come parte dell'installazione, il file di estensione .tar.gz viene salvato nel percorso seguente: /opt/mssql-extensibility/lib/java-lang-extension.tar.gz.

Per creare un linguaggio esterno Java, eseguire l'istruzione T-SQL seguente in 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

Autorizzazioni per eseguire il linguaggio esterno

Per eseguire il codice Java, un utente deve disporre dell'autorizzazione per l'esecuzione di script esterni in quel linguaggio specifico.

Per altre informazioni, vedere CREATE EXTERNAL LANGUAGE.

Creare librerie esterne

Usare CREATE EXTERNAL LIBRARY per creare una libreria esterna per i file .jar. SQL Server ha accesso ai .jar file e non è necessario impostare autorizzazioni speciali su classpath.

In questo esempio vengono create due librerie esterne. una per l'SDK e l'altra per il codice Java RegEx.

  1. Il file mssql-java-lang-extension.jar JAR SDK viene installato come parte di SQL Server 2019 (15.x) e versioni successive, sia in Windows che in Linux.

    • Percorso di installazione predefinito in Windows: <instance installation home directory>\MSSQL\Binn\mssql-java-lang-extension.jar

    • Percorso di installazione predefinito in Linux: /opt/mssql/lib/mssql-java-lang-extension.jar

    Il codice è anche open source ed è disponibile nel repository GitHub delle estensioni del linguaggio di SQL Server. Per altre informazioni, vedere Microsoft Extensibility SDK per Java per SQL Server.

  2. Creare una libreria esterna per l'SDK.

    CREATE EXTERNAL LIBRARY sdk
    FROM (CONTENT = '<OS specific path from above>/mssql-java-lang-extension.jar')
    WITH (LANGUAGE = 'Java');
    GO
    
  3. Creare una libreria esterna per il codice RegEx.

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

Impostare le autorizzazioni

Nota

Ignorare questo passaggio se si usano librerie esterne nel passaggio precedente. Il metodo consigliato consiste nel creare una libreria esterna dal file .jar.

Se non si vogliono usare librerie esterne, è necessario impostare le autorizzazioni necessarie. L'esecuzione dello script ha esito positivo solo se le identità del processo hanno accesso al codice. Per altre informazioni sull'impostazione di autorizzazioni, vedere la guida all'installazione.

In Linux

Concedere autorizzazioni di lettura/esecuzione per il classpath all'utente mssql_satellite .

In Windows

Concedere autorizzazioni di lettura ed esecuzione a SQLRUserGroup e l'ID di sicurezza per Tutti i pacchetti applicazioni per la cartella contenente il codice Java compilato.

L'intero albero deve avere le autorizzazioni, dal padre di livello radice all'ultima sottocartella.

  1. Fare clic con il pulsante destro del mouse sulla cartella, ad esempio C:\myJavaCode, e quindi scegliere Proprietà>Sicurezza.
  2. Seleziona Modifica
  3. Selezionare Aggiungi.
  4. In Seleziona utenti, computer, account servizio o gruppi:
    1. Selezionare Tipi di oggetto e assicurarsi che siano selezionati i principi di sicurezza predefiniti e i gruppi .
    2. Selezionare Percorsi per selezionare il nome del computer locale nella parte superiore dell'elenco.
  5. Immettere SQLRUserGroup, controllare il nome e selezionare OK per aggiungere il gruppo.
  6. Immettere TUTTI I PACCHETTI DELL'APPLICAZIONE, controllare il nome e selezionare OK per aggiungere. Se il nome non viene risolto, rivedere il passaggio relativo ai percorsi. L'ID di sicurezza è locale per il computer in uso.

Assicurarsi che entrambe le identità di sicurezza dispongano delle autorizzazioni Lettura ed Esecuzione per la cartella e la pkg sottocartella.

Chiamare la classe Java

Creare una stored procedure che chiama sp_execute_external_script per chiamare il codice Java da SQL Server. script Nel parametro definire quale package.class chiamare. Nel codice seguente la classe appartiene a un pacchetto denominato e a un file di classe denominato pkgRegexSample.java.

Nota

Il codice non definisce il metodo da chiamare. Per impostazione predefinita, verrà chiamato il execute metodo . Ciò significa che è necessario seguire l'interfaccia dell'SDK e implementare un metodo execute nella classe Java, se si vuole essere in grado di chiamare la classe da SQL Server.

La stored procedure accetta una query di input (set di dati di input) e un'espressione regolare e restituisce le righe che hanno soddisfatto l'espressione regolare specificata. Usa un'espressione [Jj]ava regolare che controlla se un testo contiene la parola Java o 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
    EXEC 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

Risultati

Dopo aver eseguito la chiamata, si dovrebbe ottenere un set di risultati con due delle righe.

Screenshot of Results from Java sample.

Se si riceve un errore

  • Quando si compilano le classi, la pkg sottocartella deve contenere il codice compilato per tutte e tre le classi.

  • Se non si usano librerie esterne, controllare le autorizzazioni per ogni cartella, dalla root cartella alla pkg sottocartella, per assicurarsi che le identità di sicurezza che eseguono il processo esterno dispongano dell'autorizzazione per leggere ed eseguire il codice.