Sdílet prostřednictvím


Kurz: Hledání řetězce pomocí regulárních výrazů (regex) v Javě

Platí pro: SQL Server 2019 (15.x) a novější verze

V tomto kurzu se dozvíte, jak pomocí rozšíření SQL Server Language Extensions vytvořit třídu Java, která přijímá dva sloupce (ID a text) z SQL Serveru a regulární výraz (regex) jako vstupní parametr. Třída vrátí dva sloupce zpět na SQL Server (ID a text).

Pro daný text v textovém sloupci odeslaném do třídy Java kód zkontroluje, jestli je daný regulární výraz splněný, a vrátí tento text společně s původním ID.

Tento vzorový kód používá regulární výraz, který kontroluje, zda text obsahuje slovo Java nebo java.

Požadavky

Pro účely tohoto kurzu stačí kompilace javac příkazového řádku.

Vytvoření ukázkových dat

Nejprve vytvořte novou databázi a naplňte testdata tabulku sloupciID.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

Vytvoření hlavní třídy

V tomto kroku vytvořte volaný RegexSample.java soubor třídy a zkopírujte do tohoto souboru následující kód Java.

Tato hlavní třída importuje sadu SDK, což znamená, že soubor JAR stažený v kroku 1 musí být zjistitelný z této třídy.

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

Kompilace a vytvoření souboru .jar

Zabalte třídy a závislosti do .jar souborů. Většina prostředí Java IDEs (například Eclipse nebo IntelliJ) podporuje generování .jar souborů při sestavování nebo kompilaci projektu. Pojmenujte .jar soubor regex.jar.

Pokud nepoužíváte prostředí Java IDE, můžete soubor vytvořit .jar ručně. Další informace najdete v tématu Vytvoření souboru java .jar ze souborů třídy.

Poznámka:

Tento kurz používá balíčky. Řádek package pkg; v horní části třídy zajišťuje, že se zkompilovaný kód uloží do podsložky s názvem pkg. Pokud používáte integrované vývojové prostředí (IDE), zkompilovaný kód se automaticky uloží do této složky. Pokud používáte javac k ruční kompilaci tříd, musíte umístit zkompilovaný kód do pkg složky.

Vytvoření externího jazyka

V databázi musíte vytvořit externí jazyk. Externí jazyk je objekt v oboru databáze, což znamená, že externí jazyky, jako je Java, je potřeba vytvořit pro každou databázi, ve které ji chcete použít.

Vytvoření externího jazyka ve Windows

Pokud používáte Windows, následujícím postupem vytvořte externí jazyk pro Javu.

  1. Vytvořte soubor .zip obsahující příponu.

    V rámci instalace SQL Serveru ve Windows je soubor s příponou .zip Java nainstalován v tomto umístění: [SQL Server install path]\MSSQL\Binn\java-lang-extension.zip. Tento soubor ZIP obsahuje javaextension.dllsoubor .

  2. Ze souboru .zip vytvořte jazyk Java pro externí jazyk:

    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
    

Vytvoření externího jazyka v Linuxu

V rámci nastavení je soubor přípony .tar.gz uložen pod následující cestou: /opt/mssql-extensibility/lib/java-lang-extension.tar.gz.

Pokud chcete vytvořit externí jazyk Java, spusťte v Linuxu následující příkaz T-SQL:

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

Oprávnění ke spuštění externího jazyka

Pokud chcete spustit kód Java, musí mít uživatel udělené provádění externích skriptů v daném konkrétním jazyce.

Další informace naleznete v tématu VYTVOŘENÍ EXTERNÍHO JAZYKA.

Vytváření externích knihoven

Pomocí příkazu CREATE EXTERNAL LIBRARY vytvořte externí knihovnu pro vaše .jar soubory. SQL Server má přístup k .jar souborům a nemusíte nastavovat žádná zvláštní oprávnění k souboru classpath.

V této ukázce vytvoříte dvě externí knihovny. Jeden pro sadu SDK a druhý pro kód RegEx Java.

  1. Soubor mssql-java-lang-extension.jar JAR sady SDK je nainstalován jako součást SQL Serveru 2019 (15.x) a novějších verzí ve Windows i Linuxu.

    • Výchozí instalační cesta ve Windows: <instance installation home directory>\MSSQL\Binn\mssql-java-lang-extension.jar

    • Výchozí instalační cesta v Linuxu: /opt/mssql/lib/mssql-java-lang-extension.jar

    Kód je také opensourcový a najdete ho v úložišti SQL Server Language Extensions na GitHubu. Další informace naleznete v tématu Microsoft Extensibility SDK for Java for SQL Server.

  2. Vytvořte externí knihovnu pro sadu SDK.

    CREATE EXTERNAL LIBRARY sdk
    FROM (CONTENT = '<OS specific path from above>/mssql-java-lang-extension.jar')
    WITH (LANGUAGE = 'Java');
    GO
    
  3. Vytvořte externí knihovnu pro kód RegEx.

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

Nastavení oprávnění

Poznámka:

Tento krok přeskočte, pokud v předchozím kroku používáte externí knihovny. Doporučeným způsobem je vytvořit z vašeho .jar souboru externí knihovnu.

Pokud nechcete používat externí knihovny, musíte nastavit potřebná oprávnění. Spuštění skriptu proběhne úspěšně pouze v případě, že identita procesu má přístup k vašemu kódu. Další informace o nastavení oprávnění najdete v průvodci instalací.

V Linuxu

Udělte uživateli oprávnění ke čtení a spouštění.mssql_satellite

V systému Windows

Udělte uživateli SQLRUserGroup a všem balíčkům aplikací identifikátor SID pro složku obsahující váš zkompilovaný kód Java oprávnění ke čtení a spuštění.

Celý strom musí mít oprávnění od kořenové nadřazené k poslední podsložce.

  1. Klikněte pravým tlačítkem myši na složku (napříkladC:\myJavaCode) a zvolte Zabezpečení vlastností>.
  2. Vyberte Upravit.
  3. Vyberte Přidat.
  4. V části Vybrat uživatele, počítač, účty služeb nebo skupiny:
    1. Vyberte typy objektů a ujistěte se, že jsou vybrány předdefinované principy zabezpečení a skupiny .
    2. Výběrem možnosti Umístění vyberte název místního počítače v horní části seznamu.
  5. Zadejte SQLRUserGroup, zkontrolujte název a vyberte OK a přidejte skupinu.
  6. Zadejte VŠECHNY BALÍČKY APLIKACÍ, zkontrolujte název a vyberte OK , které chcete přidat. Pokud se název nevyřeší, přejděte ke kroku Umístění. Identifikátor SID je místní pro váš počítač.

Ujistěte se, že obě identity zabezpečení mají oprávnění ke čtení a spuštění složky a pkg podsložky.

Volání třídy Java

Vytvořte uloženou proceduru, která volá sp_execute_external_script kód Java z SQL Serveru. V parametru script definujte, který package.class chcete volat. V následujícím kódu patří třída do balíčku volaný pkg a soubor třídy s názvem RegexSample.java.

Poznámka:

Kód nedefinuje, kterou metodu se má volat. Ve výchozím nastavení execute bude volána metoda. To znamená, že potřebujete postupovat podle rozhraní sady SDK a implementovat metodu execute ve třídě Java, pokud chcete být schopni volat třídu z SQL Serveru.

Uložená procedura přebírá vstupní dotaz (vstupní datovou sadu) a regulární výraz a vrací řádky, které splňují daný regulární výraz. Používá regulární výraz [Jj]ava , který kontroluje, zda text obsahuje slovo Java nebo 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

Po provedení volání byste měli získat sadu výsledků se dvěma řádky.

Snímek obrazovky s ukázkou Výsledky z Javy

Pokud se zobrazí chyba

  • Při kompilaci tříd pkg by podsložka měla obsahovat zkompilovaný kód pro všechny tři třídy.

  • Pokud nepoužíváte externí knihovny, zkontrolujte oprávnění ke každé složce z rootpkg podsložky a ujistěte se, že identity zabezpečení spuštěné externím procesem mají oprávnění ke čtení a spouštění kódu.