Dela via


Självstudie: Sök efter en sträng med reguljära uttryck (regex) i Java

Gäller för: SQL Server 2019 (15.x) och senare versioner

Den här självstudien visar hur du använder SQL Server Language Extensions för att skapa en Java-klass som tar emot två kolumner (ID och text) från SQL Server och ett reguljärt uttryck (regex) som indataparameter. Klassen returnerar två kolumner tillbaka till SQL Server (ID och text).

För en viss text i textkolumnen som skickas till Java-klassen kontrollerar koden om det angivna reguljära uttrycket uppfylls och returnerar texten tillsammans med det ursprungliga ID:t.

Den här exempelkoden använder ett reguljärt uttryck som kontrollerar om en text innehåller ordet Java eller java.

Förutsättningar

Kommandoradskompilering med hjälp av javac räcker för den här självstudien.

Skapa exempeldata

Skapa först en ny databas och fyll i en testdata tabell med ID och text kolumner.

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

Skapa huvudklassen

I det här steget skapar du en klassfil med namnet RegexSample.java och kopierar följande Java-kod till filen.

Den här huvudklassen importerar SDK:n, vilket innebär att jar-filen som laddades ned i steg1 måste kunna identifieras från den här klassen.

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();
    }
}

Kompilera och skapa en .jar fil

Paketera dina klasser och beroenden i en .jar fil. De flesta Java-ID:er (till exempel Eclipse eller IntelliJ) stöder generering .jar av filer när du skapar eller kompilerar projektet. Ge filen regex.jarnamnet .jar .

Om du inte använder en Java IDE kan du skapa en .jar fil manuellt. Mer information finns i Skapa en Java-.jar fil från klassfiler.

Anmärkning

I den här självstudien används paket. Raden package pkg; överst i klassen ser till att den kompilerade koden sparas i en undermapp med namnet pkg. Om du använder en IDE sparas den kompilerade koden automatiskt i den här mappen. Om du använder javac för att kompilera klasserna manuellt måste du placera den kompilerade koden i pkg mappen.

Skapa externt språk

Du måste skapa ett externt språk i databasen. Det externa språket är ett databasomfattningsobjekt, vilket innebär att externa språk som Java måste skapas för varje databas som du vill använda det i.

Skapa ett externt språk i Windows

Om du använder Windows följer du de här stegen för att skapa ett externt språk för Java.

  1. Skapa en .zip fil som innehåller tillägget.

    Som en del av SQL Server-installationen i Windows installeras Java-tilläggsfilen .zip på den här platsen: [SQL Server install path]\MSSQL\Binn\java-lang-extension.zip. Den här zip-filen innehåller javaextension.dll.

  2. Skapa ett externt språk i Java från .zip-filen:

    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
    

Skapa ett externt språk i Linux

Som en del av installationen sparas filnamnstillägget .tar.gz under följande sökväg: /opt/mssql-extensibility/lib/java-lang-extension.tar.gz.

Om du vill skapa ett externt språk i Java kör du följande T-SQL-instruktion i 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

Behörigheter för att köra externt språk

För att köra Java-kod måste en användare beviljas extern skriptkörning på det specifika språket.

Mer information finns i SKAPA EXTERNT SPRÅK.

Skapa externa bibliotek

Använd SKAPA EXTERNT BIBLIOTEK för att skapa ett externt bibliotek för dina .jar filer. SQL Server har åtkomst till .jar filerna och du behöver inte ange några särskilda behörigheter till classpath.

I det här exemplet skapar du två externa bibliotek. En för SDK och en för RegEx Java-koden.

  1. SDK-jar-filen mssql-java-lang-extension.jar installeras som en del av SQL Server 2019 (15.x) och senare versioner på både Windows och Linux.

    • Standardinstallationssökväg i Windows: <instance installation home directory>\MSSQL\Binn\mssql-java-lang-extension.jar

    • Standardinstallationssökväg i Linux: /opt/mssql/lib/mssql-java-lang-extension.jar

    Koden är också öppen källkod och finns på GITHub-lagringsplatsen för SQL Server Language Extensions. Mer information finns i Microsoft Extensibility SDK för Java för SQL Server.

  2. Skapa ett externt bibliotek för SDK:t.

    CREATE EXTERNAL LIBRARY sdk
    FROM (CONTENT = '<OS specific path from above>/mssql-java-lang-extension.jar')
    WITH (LANGUAGE = 'Java');
    GO
    
  3. Skapa ett externt bibliotek för RegEx-koden.

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

Ange behörigheter

Anmärkning

Hoppa över det här steget om du använder externa bibliotek i föregående steg. Det rekommenderade sättet är att skapa ett externt bibliotek från filen .jar .

Om du inte vill använda externa bibliotek måste du ange nödvändiga behörigheter. Skriptkörningen lyckas bara om processidentiteterna har åtkomst till din kod. Mer information om hur du anger behörigheter finns i installationsguiden.

På Linux

Bevilja läs-/körningsbehörigheter på klassökvägen till mssql_satellite användaren.

På Windows

Bevilja behörigheten "Läs och kör" till SQLRUserGroup och SID för alla programpaket i mappen som innehåller din kompilerade Java-kod.

Hela trädet måste ha behörigheter, från rot överordnad till den sista undermappen.

  1. Högerklicka på mappen (till exempel C:\myJavaCode) och välj Egenskaper>Säkerhet.
  2. Välj Redigera.
  3. Välj Lägg till.
  4. I Välj användare, dator, tjänstkonton eller grupper:
    1. Välj Objekttyper och kontrollera att inbyggda säkerhetsprinciper och grupper är markerade.
    2. Välj Platser för att välja namnet på den lokala datorn överst i listan.
  5. Ange SQLRUserGroup, kontrollera namnet och välj OK för att lägga till gruppen.
  6. Ange ALLA PROGRAMPAKET, kontrollera namnet och välj OK att lägga till. Om namnet inte matchar går du tillbaka till steget Platser. SID är lokalt för din dator.

Kontrollera att båda säkerhetsidentiteterna har läs- och körningsbehörigheter för mappen och undermappen pkg .

Anropa Java-klassen

Skapa en lagrad procedur som anropar sp_execute_external_script för att anropa Java-koden från SQL Server. I parametern script definierar du vilket package.class du vill anropa. I följande kod tillhör klassen ett paket med namnet pkg och en klassfil med namnet RegexSample.java.

Anmärkning

Koden definierar inte vilken metod som ska anropas. Som standard execute anropas metoden. Det innebär att du måste följa SDK-gränssnittet och implementera en körningsmetod i Java-klassen om du vill kunna anropa klassen från SQL Server.

Den lagrade proceduren tar en indatafråga (indatauppsättning) och ett reguljärt uttryck och returnerar de rader som uppfyllde det angivna reguljära uttrycket. Det använder ett reguljärt uttryck [Jj]ava som kontrollerar om en text innehåller ordet Java eller 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

När du har kört anropet bör du få en resultatuppsättning med två av raderna.

Skärmbild av resultat från Java-exempel.

Om du får ett fel

  • När du kompilerar dina klasser ska undermappen pkg innehålla den kompilerade koden för alla tre klasserna.

  • Om du inte använder externa bibliotek kontrollerar du behörigheterna för varje mapp, från mappen root till pkg under, för att säkerställa att säkerhetsidentiteterna som kör den externa processen har behörighet att läsa och köra koden.