Écriture de procédures stockées dans Snowpark (Java)

Avec cette fonctionnalité en avant-première, vous pouvez écrire une procédure stockée en Java. Vous pouvez utiliser la bibliothèque Snowpark dans votre procédure stockée pour effectuer des requêtes, des mises à jour et d’autres travaux sur les tables dans Snowflake.

Cette rubrique explique comment écrire une procédure stockée en Java.

Dans ce chapitre :

Introduction

Avec les procédures stockées de Snowpark, vous pouvez construire et exécuter votre pipeline de données dans Snowflake, en utilisant un entrepôt Snowflake comme cadre de calcul. Pour le code de votre pipeline de données, vous utilisez l’API Snowpark pour Java pour écrire des procédures stockées. Pour planifier l’exécution de ces procédures stockées, vous utilisez des tâches.

Dans cette avant-première, les procédures stockées de Snowpark ont les limitations suivantes :

  • La simultanéité n’est pas prise en charge dans les procédures stockées. Par exemple, à partir de votre procédure stockée, vous ne pouvez pas soumettre de requêtes à partir de plusieurs threads.

  • Si vous exécutez votre procédure stockée à partir d’une tâche, vous devez spécifier un entrepôt lors de la création de la tâche. (Vous ne pouvez pas utiliser les ressources de calcul gérées par Snowflake pour exécuter la tâche).

  • Vous ne pouvez pas utiliser certaines des APIs de Snowpark dans votre procédure stockée. Pour obtenir la liste des APIs non prises en charge, voir Accès aux données dans Snowflake à partir de votre procédure stockée.

Les sections suivantes fournissent de plus amples informations sur les procédures stockées de Snowpark pour Java.

Conditions préalables

Vous devez utiliser la version 1.3.0 ou une version plus récente de la bibliothèque Snowpark.

Si vous écrivez une procédure stockée précompilée, vous devez compiler vos classes pour qu’elles s’exécutent dans la version 11.x de Java.

Configuration de votre environnement de développement pour Snowpark

Ensuite, configurez votre environnement de développement pour utiliser la bibliothèque Snowpark. Voir Configuration de votre environnement de développement pour Snowpark Java.

Choisir de créer une procédure stockée en ligne ou précompilée

Comme c’est le cas avec les UDFs Java, vous pouvez soit créer une procédure stockée en ligne, soit une procédure stockée précompilée.

  • Dans une procédure stockée en ligne, vous écrivez votre code Java dans la clause AS de l’instruction CREATE PROCEDURE. Par exemple :

    CREATE OR REPLACE PROCEDURE MYPROC(fromTable STRING, toTable STRING, count INT)
      RETURNS STRING
      LANGUAGE JAVA
      RUNTIME_VERSION = '11'
      PACKAGES = ('com.snowflake:snowpark:latest')
      HANDLER = 'MyJavaClass.run'
      AS
      $$
        import com.snowflake.snowpark_java.*;
    
        public class MyJavaClass {
          public String run(Session session, String fromTable, String toTable, int count) {
            session.table(fromTable).limit(count).write().saveAsTable(toTable);
            return "SUCCESS";
          }
        }
      $$;
    

    Note

    Pour une exécution plus rapide lors d’appels répétés, vous pouvez définir TARGET_PATH à l’emplacement d’un fichier JAR dans lequel Snowflake doit enregistrer les classes compilées. Voir Création de la procédure stockée.

  • Dans une procédure stockée précompilée, vous écrivez votre code Java dans un fichier source .java.

    Par exemple :

    import com.snowflake.snowpark_java.*;
    
    public class MyJavaClass {
      public String run(Session session, String fromTable, String toTable, int count) {
        session.table(fromTable).limit(count).write().saveAsTable(toTable);
        return "SUCCESS";
      }
    }
    

    Vous compilez ensuite votre code, empaquetez les classes dans un fichier JAR, téléchargez le fichier JAR dans une zone de préparation et exécutez la commande CREATE PROCEDURE, qui pointe vers le fichier JAR sur la zone de préparation. Par exemple :

    CREATE OR REPLACE PROCEDURE MYPROC(value INT, fromTable STRING, toTable STRING, count INT)
      RETURNS INT
      LANGUAGE JAVA
      RUNTIME_VERSION = '11'
      PACKAGES = ('com.snowflake:snowpark:latest')
      IMPORTS = ('@mystage/MyCompiledJavaCode.jar')
      HANDLER = 'MyJavaClass.run';
    

Écriture du code Java pour la procédure stockée

Pour le code de votre procédure stockée, vous devez écrire une méthode Java. Les sections suivantes fournissent des directives pour l’écriture de votre code :

Planification de l’écriture de votre procédure stockée

Le code Java de votre procédure stockée présente les mêmes contraintes que le code d’une UDF Java. Lorsque vous planifiez l’écriture de vos procédures stockées, vous devez tenir compte de ces contraintes.

Limiter la quantité de mémoire consommée

Comme c’est le cas avec les UDFs Java, Snowflake impose des limites à une méthode ou une fonction en matière de quantité de mémoire nécessaire.

Dans votre méthode, vous devez éviter de consommer trop de mémoire.

Écrire du code en respectant le niveau de « thread safety »

De même, comme c’est le cas avec les UDFs Java, vous devez vous assurer que votre méthode respecte le niveau de « thread safety ».

Comprendre les restrictions de sécurité

Votre méthode s’exécute dans un moteur restreint, vous devez donc suivre les mêmes règles que celles documentées pour les UDFs Java.

Décider d’utiliser les droits du propriétaire ou les droits de l’appelant

En outre, lorsque vous planifiez l’écriture de votre procédure stockée, déterminez si vous souhaitez que la procédure stockée s’exécute avec les droits de l’appelant ou les droits du propriétaire.

Écriture de la classe

La méthode que vous définissez doit faire partie d’une classe.

Lorsque vous écrivez la classe, notez ce qui suit :

  • La classe et la méthode ne doivent pas être protégées ou privées.

  • Si la méthode n’est pas statique et que vous souhaitez définir un constructeur, définissez un constructeur à zéro argument pour la classe. Snowflake appelle ce constructeur à zéro argument au moment de l’initialisation pour créer une instance de votre classe.

  • Vous pouvez définir différentes méthodes pour différentes procédures stockées dans la même classe.

Écriture de la méthode

Lorsque vous écrivez la méthode pour la procédure stockée, notez ce qui suit :

  • Spécifiez l’objet Snowpark Session comme premier argument de votre méthode.

    Lorsque vous appelez votre procédure stockée, Snowflake crée automatiquement un objet Session et le transmet à votre procédure stockée. (Vous ne pouvez pas créer l’objet Session vous-même).

  • Pour le reste des arguments et pour la valeur de retour, utilisez les types Java qui correspondent aux types de données Snowflake.

  • Votre méthode doit renvoyer une valeur. Pour les procédures stockées en Java, une valeur de retour est requise.

Accès aux données dans Snowflake à partir de votre procédure stockée

Pour accéder aux données dans Snowflake, utilisez les APIs de bibliothèque Snowpark.

Lors du traitement d’un appel à votre procédure stockée Java, Snowflake crée un objet Snowpark Session et transmet cet objet à la méthode de votre procédure stockée.

Comme c’est le cas avec les procédures stockées dans d’autres langages, le contexte de la session (par exemple, les privilèges, la base de données et le schéma actuels, etc.) est déterminé par le fait que la procédure stockée s’exécute avec les droits de l’appelant ou les droits du propriétaire. Pour plus de détails, voir État de la session.

Vous pouvez utiliser cet objet Session pour appeler des APIs dans la bibliothèque Snowpark. Par exemple, vous pouvez créer un DataFrame pour une table ou exécuter une instruction SQL.

Voir le Guide du développeur Snowpark pour Java pour plus d’informations.

Note

Vous ne pouvez pas utiliser les APIs Snowpark suivantes dans une procédure stockée :

Voici un exemple de méthode Java qui copie un nombre donné de lignes d’une table vers une autre table. La méthode accepte les arguments suivants :

  • Un objet Session Snowpark

  • Le nom de la table à partir de laquelle les lignes doivent être copiées

  • Le nom de la table dans laquelle les lignes doivent être enregistrées

  • Le nombre de lignes à copier

La méthode dans cet exemple renvoie une chaîne.

import com.snowflake.snowpark_java.*;

public class MyClass
{
  public String myMethod(Session session, String fromTable, String toTable, int count)
  {
    session.table(fromTable).limit(count).write().saveAsTable(toTable);
    return "Success";
  }
}

Accès à d’autres classes et fichiers de ressources

Si votre code dépend de classes définies en dehors de la procédure stockée (par exemple, des classes dans un fichier JAR distinct) ou de fichiers de ressources, vous devez charger ces fichiers dans une zone de préparation afin qu’ils soient disponibles lors de l’exécution de la procédure stockée.

Plus tard, lors de l’exécution de l’instruction CREATE PROCEDURE, utilisez la clause IMPORTS pour pointer vers ces fichiers.

Préparation d’une procédure stockée précompilée

Si vous envisagez de créer une procédure stockée précompilée (plutôt qu’une procédure stockée en ligne), vous devez compiler et empaqueter vos classes dans un fichier JAR. Vous devez ensuite charger le fichier JAR vers une zone de préparation.

Compilation et empaquetage de votre code Java

Pour faciliter la configuration de votre procédure stockée, créez un fichier JAR qui contient toutes les dépendances nécessaires à votre procédure stockée. Plus tard, vous devrez charger le fichier JAR vers une zone de préparation et faire pointer vers le fichier JAR à partir de votre instruction CREATE PROCEDURE. Ce processus est plus simple si vous avez moins de fichiers JAR à charger et vers lesquels pointer.

Les sections suivantes fournissent quelques conseils sur la création d’un fichier JAR qui contient toutes les dépendances :

Utilisation de Maven pour construire un fichier JAR avec des dépendances

Si vous utilisez Maven pour construire et empaqueter votre code, vous pouvez utiliser le plugin Maven Assembly pour créer un fichier JAR contenant toutes les dépendances.

  1. Dans le répertoire de votre projet (par exemple hello-snowpark/), créez un sous-répertoire nommé assembly/.

  2. Dans ce répertoire, créez un fichier descripteur d’assemblage qui spécifie que vous voulez inclure les dépendances dans votre fichier JAR.

    Pour un exemple, voir jar-with-dependencies.

  3. Dans le descripteur d’assemblage, ajoutez un élément <dependencySet> qui exclut la bibliothèque Snowpark de votre fichier JAR.

    Par exemple :

    <assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
      <id>jar-with-dependencies</id>
      <formats>
         <format>jar</format>
      </formats>
      <includeBaseDirectory>false</includeBaseDirectory>
      <dependencySets>
        <dependencySet>
          <outputDirectory>/</outputDirectory>
          <useProjectArtifact>false</useProjectArtifact>
          <unpack>true</unpack>
          <scope>provided</scope>
          <excludes>
            <exclude>com.snowflake:snowpark</exclude>
          </excludes>
        </dependencySet>
      </dependencySets>
    </assembly>
    

    Pour plus d’informations sur les éléments d’un descripteur d’assemblage, voir Format du descripteur d’assemblage.

  4. Dans votre fichier pom.xml, sous <project> » <build> » <plugins>, ajoutez un élément <plugin> pour le plugin Maven Assembly.

    En outre, sous <configuration> » <descriptors>, ajoutez un <descriptor> qui pointe vers le fichier de descripteur d’assemblage que vous avez créé aux étapes précédentes.

    Par exemple :

    <project>
      [...]
      <build>
        [...]
        <plugins>
          <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.3.0</version>
            <configuration>
              <descriptors>
                <descriptor>src/assembly/jar-with-dependencies.xml</descriptor>
              </descriptors>
            </configuration>
            [...]
          </plugin>
          [...]
        </plugins>
        [...]
      </build>
      [...]
    </project>
    

Utiliser d’autres outils pour construire un fichier JAR avec des dépendances

Si vous n’utilisez pas Maven, consultez la documentation de votre outil de construction pour obtenir des instructions sur la construction d’un fichier JAR avec toutes les dépendances.

Par exemple, si vous utilisez un projet IntelliJ IDEA, consultez les instructions sur la mise en place d’une configuration d’artefact.

Chargement de fichiers vers une zone de préparation

Ensuite, chargez les fichiers requis pour votre procédure stockée vers une zone de préparation :

  1. Choisissez une zone de préparation pour vos fichiers.

    Vous pouvez utiliser une zone de préparation externe ou interne nommée. Si vous prévoyez d’utiliser la commande PUT pour charger les fichiers, utilisez une zone de préparation interne nommée. (La commande PUT ne prend pas en charge le chargement de fichiers vers des zones de préparation externes.)

    Vous pouvez utiliser une zone de préparation existante ou alors en créer une nouvelle en exécutant CREATE STAGE. Par exemple, la commande suivante crée une nouvelle zone de préparation interne nommée mystage :

    CREATE STAGE mystage;
    

    Note

    Le propriétaire de la procédure stockée doit avoir le privilège READ sur la zone de préparation.

  2. Utilisez la commande PUT pour charger les fichiers suivants vers cette zone de préparation :

    • Le fichier JAR contenant votre code Java compilé.

    • Tout autre fichier dont dépend votre procédure stockée.

    Par exemple :

    PUT file:///Users/MyUserName/myjar.jar
            @mystage
            AUTO_COMPRESS = FALSE
            OVERWRITE = TRUE
            ;
    

    Note

    Si vous omettez AUTO_COMPRESS = FALSE, la commande PUT compresse automatiquement le fichier. Le nom du fichier compressé sur la zone de préparation sera myjar.jar.gz. Plus tard, lorsque vous exécuterez la commande CREATE PROCEDURE, vous devrez spécifier le nom de fichier avec cette extension .gz dans la clause IMPORTS.

Notez que si vous supprimez ou renommez le fichier JAR contenant votre code Java compilé, vous ne pourrez plus appeler la procédure stockée.

Si vous devez mettre à jour votre fichier JAR, alors :

  • Mettez-le à jour tant qu’aucun appel vers la procédure stockée ne peut être fait.

  • Ajoutez la clause OVERWRITE=TRUE à la commande PUT.

Création de la procédure stockée

Ensuite, exécutez l’instruction CREATE PROCEDURE pour créer une procédure stockée pour votre méthode. Définissez les paramètres énumérés dans le tableau ci-dessous.

Paramètre

Description

[ nom_argument type_données_argument [, ... ] ]

  • Omettez l’argument pour l’objet Snowpark Session. Comme mentionné précédemment, il ne s’agit pas d’un paramètre formel que vous spécifiez dans CREATE PROCEDURE ou CALL. Lorsque vous appelez votre procédure stockée, Snowflake crée un objet Session et le transmet à votre procédure stockée.

  • Pour les types de données des autres arguments, utilisez les types de données Snowflake qui correspondent aux types Java des arguments de votre méthode.

RETURNS type_données_résultat

Spécifiez RETURNS avec le type de données Snowflake de votre valeur de retour.

LANGUAGE JAVA

Vous devez le spécifier pour indiquer que le code de votre procédure stockée est écrit en Java.

RUNTIME_VERSION = '11'

Vous devez spécifier ceci pour indiquer que votre procédure stockée utilise Java 11.

PACKAGES = ( 'nom_paquet' )

Dans cette liste, incluez le paquet pour la version de la bibliothèque Snowpark que vous voulez utiliser.

Spécifiez le nom de paquet entièrement qualifié pour la bibliothèque Snowpark dans le format suivant :

com.snowflake:snowpark:<version>

Par exemple :

  • Pour utiliser la dernière version de Snowpark :

    PACKAGES = ('com.snowflake:snowpark:latest')
    
  • Pour utiliser la version 1.4.0 de Snowpark :

    PACKAGES = ('com.snowflake:snowpark:1.4.0')

Note

Lors de la création d’une nouvelle procédure stockée, spécifiez la version 1.3.0 ou ultérieure.

Pour obtenir la liste des paquets et des versions pris en charge, interrogez la vue INFORMATION_SCHEMA.PACKAGES pour les lignes comportant LANGUAGE = 'java'. Par exemple :

select * from information_schema.packages where language = 'java';

IMPORTS = ( 'fichier' [, 'fichier' ... ] )

Si votre procédure stockée dépend de fichiers JAR que vous avez chargés vers un emplacement de zone de préparation, incluez ces fichiers dans cette liste.

Si vous écrivez une procédure stockée en ligne, vous pouvez omettre cette clause, sauf si votre code dépend de classes définies en dehors de la procédure stockée ou de fichiers de ressources.

Si vous écrivez une procédure stockée précompilée, vous devez également inclure le fichier JAR contenant la définition de la procédure stockée.

HANDLER = 'nom_méthode'

Définissez-le comme le nom entièrement qualifié de votre méthode Java.

TARGET_PATH = 'fichier_jar'

Si vous écrivez une procédure stockée en ligne et que vous ne voulez pas que Snowflake recompile votre code à chaque appel, vous pouvez le définir comme le fichier JAR que Snowflake doit créer pour votre code compilé.

Il doit s’agir d’un chemin sur une zone de préparation pour laquelle vous avez des privilèges WRITE.

EXECUTE AS CALLER

Si vous avez prévu de configurer la procédure stockée pour utiliser les droits de l’appelant, ajoutez ce paramètre.

Sinon, si vous voulez utiliser les droits du propriétaire, omettez ce paramètre.

Les exemples suivants créent des procédures stockées en Java.

Exemple 1 : procédure stockée en ligne :

CREATE OR REPLACE PROCEDURE myProc(fromTable STRING, toTable STRING, count INT)
RETURNS STRING
LANGUAGE JAVA
RUNTIME_VERSION = '11'
PACKAGES = ('com.snowflake:snowpark:latest')
HANDLER = 'MyClass.myMethod'
AS
$$
  import com.snowflake.snowpark_java.*;

  public class MyClass
  {
    public String myMethod(Session session, String fromTable, String toTable, int count)
    {
      session.table(fromTable).limit(count).write().saveAsTable(toTable);
      return "Success";
    }
  }
$$;

Exemple 2 : procédure stockée précompilée qui utilise le code compilé dans le fichier JAR myjar.jar sur la zone de préparation interne mystage :

CREATE OR REPLACE PROCEDURE myProc(fromTable STRING, toTable STRING, count INT)
RETURNS STRING
LANGUAGE JAVA
RUNTIME_VERSION = '11'
PACKAGES = ('com.snowflake:snowpark:latest')
IMPORTS = ('@mystage/myjar.jar')
HANDLER = 'MyClass.myMethod';

Utilisation des procédures stockées

Pour qu’un utilisateur puisse appeler une procédure stockée, le rôle de l’utilisateur doit avoir le privilège USAGE pour la procédure stockée.

Une fois que vous avez les privilèges pour appeler la procédure stockée, vous pouvez utiliser l’instruction CALL pour appeler la procédure stockée. Par exemple :

CALL myProc('table_a', 'table_b', 5);
Revenir au début