Charger et exécuter des fonctions personnalisées dans une salle blanche

Vue d’ensemble

Vous pouvez charger des UDFs et des UDTFs Python personnalisées dans votre salle blanche et les exécuter à partir de vos modèles pour effectuer des actions de données complexes. Ces actions comprennent le machine learning ou la manipulation personnalisée des données dans une requête, dans le cadre d’une seule étape ou d’un flux à plusieurs étapes. Python est le seul langage de codage pris en charge pour les UDFs personnalisées.

Votre code importé peut importer et utiliser des paquets à partir d’un bundle de packages Python approuvés et l’APISnowpark.

Les fournisseurs et les consommateurs peuvent charger du code Python personnalisé dans une salle blanche, bien que le processus soit différent pour les fournisseurs et les consommateurs.

Cette rubrique montre comment charger et exécuter des UDFs et UDTFs Python personnalisés en tant que fournisseur ou consommateur.

Astuce

Pour obtenir des informations générales sur la manière de développer vos propres UDFs Python dans une salle blanche, consultez les rubriques suivantes :

Exécution du code chargé

Chaque bundle de code importé peut définir plusieurs fonctions qui s’appellent entre elles, mais un bundle n’expose qu’une seule fonction de gestionnaire. Cette fonction de gestionnaire peut être appelée par des modèles créés ou exécutés par quiconque utilise la salle blanche. Si le code crée des tables internes, ces tables sont accessibles comme décrit dans la section Conception de flux à plusieurs étapes.

Par exemple, si vous avez chargé une fonction nommée simple_add qui intègre deux paramètres numériques, vous pouvez l’appeler à partir d’un modèle comme illustré ici. La fonction est toujours référencée à l’aide de la cleanroom à champ d’application limité. Par exemple, un modèle pourrait appeler simple_add comme suit :

SELECT cleanroom.simple_add({{ price | sqlsafe | int }}, {{ tax | sqlsafe | int }}) ...
Copy

Astuce

Si le fournisseur veut exécuter le code ci-dessus, il doit donner un alias à toutes les colonnes SELECT qui utilisent une fonction agrégée ou personnalisée, car une table de résultats est générée en arrière-plan :

SELECT
  cleanroom.simple_add(
    {{ price | sqlsafe | int }}, {{ tax | sqlsafe | int }}
    ) AS TOTAL_ITEM_COST
...
Copy

Vous pouvez charger plusieurs fonctions dans un seul paquet, et les fonctions d’un même paquet peuvent s’appeler entre elles, mais les fonctions ne peuvent pas appeler de fonctions dans d’autres paquets. (Cependant, elles peuvent appeler les fonctions du gestionnaire). Par exemple :

Salle blanche avec deux paquets Python chargés

Paquet 1

Paquet 2

  • Fonction de gestionnaire A

  • Fonction d’assistance A1

  • Fonction d’assistance A2

  • Fonction de gestionnaire B

  • Fonction d’assistance B1

  • Fonction d’assistance B2

Remarques :

  • Le code chargé de chaque côté (fournisseur et consommateur) peut être exécuté de chaque côté.

  • Un modèle peut appeler la fonction A ou la fonction B, mais pas A1, A2, B1, B2.

  • La fonction A peut appeler la fonction B, et inversement.

  • La fonction A ne peut pas appeler B1 ou B2 et la fonction B ne peut pas appeler A1 ou A2.

  • A1 peut appeler A2 et inversement. A1 et A2 peuvent appeler B. A1 et A2 ne peuvent pas appeler B1 ou B2.

  • B1 peut appeler B2 et inversement. B1 et B2 peuvent appeler A. B1 et B2 ne peuvent pas appeler A1 ou A2.

Mise à jour ou suppression des fonctions personnalisées

Vous pouvez charger ou remplacer une fonction ou un modèle existant que vous avez chargé, mais vous ne pouvez pas supprimer une fonction ou un modèle existant. La seule façon de « supprimer » une fonction est de créer une fonction fictive avec exactement le même nom et la même signature qui réussit toujours.

Le chargement d’une fonction avec exactement la même signature que celle que vous avez chargée précédemment remplacera la fonction existante. La signature est le nom de la fonction insensible à la casse du gestionnaire externe, et les types de données de tous les paramètres, dans le même ordre. Les noms des paramètres n’ont pas d’importance. Vous ne pouvez pas remplacer une fonction téléchargée par un autre compte.

Comme la signature doit correspondre lorsque vous mettez à jour une fonction, vous ne pouvez pas modifier la signature d’une fonction existante : si vous chargez la fonction foo(name VARIANT age INTEGER), puis chargez la fonction foo(name VARIANT age FLOAT), la deuxième fonction sera ajoutée à la salle blanche en plus de la première, car les types d’arguments diffèrent.

Code soumis par le fournisseur

Les fonctions soumises par le fournisseur peuvent être chargées sous forme de code en ligne ou à partir d’une zone de préparation Snowflake. Les deux techniques sont couvertes ici.

Votre code chargé peut importer et utiliser nativement des packages à partir d’un ensemble approuvé de packages Python. Si vous avez besoin d’un package non proposé par défaut, vous devez utiliser Snowpark Container Services dans une salle blanche pour héberger votre code.

Vous ne pouvez pas voir le code du fournisseur chargé, ni même votre propre code, alors veillez à inclure une copie de ce que vous chargez exactement dans une salle blanche.

Astuce

Après avoir mis à jour le code écrit par le fournisseur, vous devez mettre à jour la directive de version par défaut, puis appeler provider.create_or_update_cleanroom_listing pour propager les changements aux consommateurs. Si vous n’appelez pas provider.create_or_update_cleanroom_listing, votre version par défaut ne sera pas mise à jour pour les consommateurs qui utilisent actuellement la salle blanche.

Voici une vue de haut niveau de la manière dont un fournisseur ajoute du code à une salle blanche :

  1. Le fournisseur crée et configure la salle blanche de manière habituelle.

  2. Le fournisseur charge le code en appelant provider.load_python_into_cleanroom. Vous pouvez charger votre code en ligne directement dans cette procédure ou charger un fichier de code dans une zone de préparation. Puis, indiquez l’emplacement de la zone de préparation dans cette procédure.

    Bien que votre code puisse inclure plusieurs fonctions, un seul gestionnaire est exposé pour chaque chargement. Pour exposer plusieurs fonctions pour les modèles, téléchargez chaque gestionnaire en appelant provider.load_python_into_cleanroom.

  3. Après chaque chargement de code réussi, une nouvelle version corrective de la salle blanche est générée. Vous devez ensuite améliorer la version par défaut en appelant provider.set_default_release_directive avec le nouveau numéro de correctif. Si la salle blanche est exposée à l’extérieur, les contrôles de sécurité sont exécutés avant d’installer votre code et vous devez appeler provider.view_cleanroom_scan_status pour confirmer que les contrôles de sécurité ont réussi avant d’incrémenter la version par défaut.

    • Si vous souhaitez charger plusieurs fonctions dans un seul correctif, vous pouvez charger en masse votre code. Cependant, les chargements en masse peuvent rendre plus difficile le débogage si le chargement présente un problème d’analyse de sécurité, parce que le fichier qui a causé le problème n’est pas signalé dans la réponse d’erreur.

  4. Vous créez et chargez un modèle personnalisé qui appelle votre code. Le modèle doit appeler la fonction de gestionnaire à l’aide du champ d’application de la cleanroom, qui est : cleanroom.my_function(...).

  5. Le consommateur exécute votre modèle de la même manière que tout autre modèle.

    Astuce

    Si le consommateur rencontre une erreur de montage lorsqu’il installe une salle blanche avec du code personnalisé, cela peut indiquer une erreur de syntaxe dans le code.

Vous trouverez des exemples de code démontrant ce flux dans la section d’exemple de code écrit par le fournisseur.

Notes importantes sur la gestion des versions

Chaque fois que le fournisseur charge une fonction, le nombre de correctifs augmente (avec une limite de 99 numéros de correctifs). Par conséquent, faites de votre mieux pour tester et déboguer rigoureusement votre code avant de l’ajouter à la salle blanche afin de réduire les mises à jour de versions au cours du développement.

Si vous mettez à jour un numéro de correctif, les clients qui utilisent l’UI des salles blanches peuvent devoir actualiser la page pour voir le changement. Les clients qui utilisent l’API devrait voir les changements immédiatement, mais cela peut prendre un certain temps en fonction des ressources disponibles. En savoir plus sur la gestion des versions des salles blanches.

Charger des fonctions en ligne écrites par le fournisseur

Vous pouvez charger le code en ligne dans le paramètre code de provider.load_python_into_cleanroom. Voici un exemple de chargement d’une fonction simple en ligne :

CALL samooha_by_snowflake_local_db.provider.load_python_into_cleanroom(
$cleanroom_name,
'simple_add',                         -- Name used to call the UDF from a template.
['first INTEGER', 'second INTEGER'],  -- Arguments of the UDF, specified as '<variable_name> <SQL type>' pairs.
['numpy', 'pandas'],                  -- Packages imported by the UDF.
'INTEGER',                            -- SQL return type of UDF.
'add_two',                            -- Handler function in your code called when external name is called.
$$
import numpy as np   # Not used, but you can load supported packages.
import pandas as pd

def add_two(first, second):
    return first + second
$$
);
Copy

Le modèle d’appel appelle cleanroom.simple_add pour appeler cette fonction. Les exemples de fonctions écrites par le fournisseur montrent comment charger du code en ligne.

Chargement de fonctions écrites par un fournisseur à partir d’une zone de préparation

Vous pouvez charger des fichiers Python dans une zone de préparation de salle blanche et faire référence à la zone de préparation lorsque vous appelez provider.load_python_into_cleanroom. Le chargement de code à partir d’une zone de préparation vous permet de développer le code de votre système local dans un éditeur, d’éviter les erreurs copier/coller lorsque vous le chargez en ligne et d’avoir un meilleur contrôle des versions. Notez que vous pouvez charger plusieurs fichiers dans un seul appel de procédure, mais qu’une seule fonction de gestionnaire est exposée pour chaque chargement.

Le code est chargé depuis une zone de préparation dans la salle blanche lorsque vous appelez load_python_into_cleanroom. Les modifications ultérieures apportées au code sur la zone de préparation ne sont pas répercutées dans la salle blanche.

Pour charger votre UDF dans une zone de préparation :

  1. Créez votre fichier .py et rendez-le disponible dans un emplacement où vous pouvez le charger dans une zone de préparation Snowsight.

  2. Pour obtenir le nom de la zone de préparation de votre salle blanche, appelez provider.get_stage_for_python_files($cleanroom_name). Cette zone de préparation est accessible par la salle blanche. Vous ne pouvez pas utiliser une zone de préparation arbitraire que vous créez.

  3. Chargez le fichier .py dans la zone de préparation de votre salle blanche. Il y a plusieurs façons de procéder, notamment en utilisant la CLI, Snowsight ou des pilotes spécifiques à la langue.

  4. Appelez provider.load_python_into_cleanroom avec l’emplacement de la zone de préparation, le gestionnaire, le nom externe, les arguments et le type de retour. Les modèles de votre salle blanche peuvent désormais appeler la fonction.

L’exemple de code suivant montre comment charger du code dans une salle blanche à partir d’une zone de préparation.

-- Save the following code as reverser.py:
--import numpy as np
--def main(some_string):
--  '''Return the reverse of a string plus a random number 1-10'''
--  return some_string[::-1] + str(np.random.randint(1,10))

-- Get the stage for your clean room.
CALL samooha_by_snowflake_local_db.provider.get_stage_for_python_files($cleanroom_name);

-- Save the file to the stage. Here is how to do it by using the Snowflake CLI
PUT file://~/reverser.py <STAGE_NAME> overwrite=True auto_compress=False;

-- Load the code from the stage into the clean room.
CALL samooha_by_snowflake_local_db.provider.load_python_into_cleanroom(
    $cleanroom_name,
    'reverse', -- Name used to call the function
    ['some_string  STRING'], -- Arguments and SQL types
    ['numpy'],               -- Any required packages
    ['/reverser.py'],        -- Relative path to file on stage
    'STRING',                -- Return type
    'reverser.main'          -- <FILE_NAME>.<FUNCTION_NAME>
);

-- Uploading code, even from a stage, increases the patch number.
CALL samooha_by_snowflake_local_db.provider.set_default_release_directive(
  $cleanroom_name, 'V1_0', <NEW_PATCH_NUMBER>);

-- Upload a template that calls the function.
CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template(
    $cleanroom_name,
    $udf_template_name,
    $$
    SELECT
      p.status,
      cleanroom.reverse(p.status)
    FROM SAMOOHA_SAMPLE_DATABASE.DEMO.CUSTOMERS AS p
    LIMIT 100;
    $$
);

-- Switch to the consumer account and run the template to see the results.
Copy

Les exemples de code écrit par le fournisseur illustrent le chargement de code à partir d’une zone de préparation.

Dépannage des erreurs de syntaxe ou des échecs d’analyse dans le code chargé

Si vous chargez une fonction qui échoue en raison d’une erreur de syntaxe, ou si une analyse de sécurité échoue, un correctif non publiable peut être généré. Par conséquent, vous devez tester soigneusement votre code avant de le charger pour vous assurer qu’il ne contient pas d’erreurs de syntaxe.

Vous pouvez voir la liste des paquets et leur état de révision en exécutant la commande SQL suivante, et en fournissant l’ID de la salle blanche à l’endroit indiqué :

SHOW VERSIONS IN APPLICATION PACKAGE samooha_cleanroom_cleanroom_id;

Analyses de sécurité

Une analyse de sécurité est exécutée après toute action qui génère une nouvelle version de correctif dans une salle blanche externe, par exemple lorsque le fournisseur télécharge Python dans la salle blanche. (Le code soumis par le consommateur, décrit sur cette page, ne déclenche pas d’analyse de sécurité). Les salles blanches internes n’effectuent pas d’analyses de sécurité, mais si vous transformez une salle blanche interne en salle blanche externe, une analyse de sécurité sera déclenchée pour ce correctif. Un correctif de salle blanche ne peut pas être publié en externe tant que le correctif n’a pas été analysé.

Snowflake Data Clean Rooms utilise le Framework d’analyse de sécurité des applications natives Snowflake. Suivez les meilleures pratiques de sécurité des applications natives pour éviter les erreurs d’analyse de sécurité.

Vous pouvez effectuer d’autres actions de création de correctifs avant que la dernière analyse de sécurité ne soit terminée. Cependant, vous devez attendre que provider.view_cleanroom_scan_status ait réussi avant de pouvoir mettre à jour la directive de version par défaut afin d’utiliser la dernière version de la salle blanche.

Chargement de plusieurs fonctions Python dans un seul correctif

Si vous souhaitez télécharger plusieurs paquets Python pouvant être appelés par des modèles dans votre salle blanche, vous pouvez appeler prepare_python_for_cleanroom plusieurs fois, puis appeler load_prepared_python_into_cleanroom une fois pour analyser, charger et générer un correctif unique pour votre salle blanche. L’exemple suivant illustre le chargement d’un UDF et d’un UDTF en utilisant le chargement en masse :

---- Add custom inline UDF ----
CALL samooha_by_snowflake_local_db.provider.prepare_python_for_cleanroom(
    $cleanroom_name,
    'get_next_status',  -- Name of the UDF. Can be different from the handler.
    ['status VARCHAR'], -- Arguments of the UDF, specified as (variable name, SQL type).
    ['numpy'],          -- Packages needed by UDF.
    [],                 -- When providing the code inline, this is an empty array.
    'VARCHAR',          -- Return type of UDF.
    'get_next_status',  -- Handler.
    $$
import numpy as np
def get_next_status(status):
  """Return the next higher status, or a random status
  if no matching status found or at the top of the list."""

  statuses = ['MEMBER', 'SILVER', 'GOLD', 'PLATINUM', 'DIAMOND']
  try:
    return statuses[statuses.index(status.upper()) + 1]
  except:
    return 'NO MATCH'
    $$
);

---- Add custom inline UDTF. ----
CALL samooha_by_snowflake_local_db.provider.prepare_python_for_cleanroom(
    $cleanroom_name,
    'get_info',  -- Name of the UDTF. Can be different from the handler.
    ['hashed_email VARCHAR', 'days_active INT', 'status VARCHAR', 'income VARCHAR'],   -- Name/Type arguments of the UDTF.
    ['numpy'],         -- Packages used by UDTF.
    [],                -- When providing the code inline, this is an empty array.
    'TABLE(hashed_email VARCHAR, months_active INT, level VARCHAR)',  -- Return type of UDTF.
    'GetSomeVals',     -- Handler class name.
$$
class GetSomeVals:
  def __init__(self):
    self.month_days = 30

  def process(self, hashed_email, days_active, status, income):
    '''Change days into rough months, and also return whether we
    think the user's membership status is lower, higher, or equal to
    what is expected, based on their income.'''

    months_active = days_active // self.month_days
    brackets = ['0-50K', '50K-100K', '100K-250K', '250K+']
    statuses = ['MEMBER', 'SILVER', 'GOLD', 'PLATINUM']
    if(statuses.index(status) < brackets.index(income)):
      level = 'low'
    elif(statuses.index(status) > brackets.index(income)):
      level = 'high'
    else:
      level = 'equal'

    yield(hashed_email, months_active, level)
$$
);

-- Upload all stored procedures.
-- Note the new patch number returned by this procedure. Keep this number for later use.
CALL samooha_by_snowflake_local_db.provider.load_prepared_python_into_cleanroom($cleanroom_name);

-- Set the release directive specified by the last load_python_into_cleanroom call.
CALL samooha_by_snowflake_local_db.provider.set_default_release_directive($cleanroom_name, 'V1_0', <PATCH_NUMBER>);
Copy

Exemples de code écrits par le fournisseur

Les exemples suivants illustrent l’ajout de UDFs et de UDTFs écrites par le fournisseur dans une salle blanche.

Téléchargez les exemples suivants, puis chargez-les sous forme de fichiers de feuilles de calcul dans votre compte Snowflake. Vous avez besoin de comptes distincts pour le fournisseur et le consommateur, chacun avec l’API de salles blanches installée. Remplacez les informations comme indiqué dans les fichiers d’exemple.

  • :download :Exemple de code fournisseur</samples/clean-rooms/provider-udf-p.sql>

  • :download :Exemple de code consommateur</samples/clean-rooms/provider-udf-c.sql>

  • :download :Chargement d’un fichier à partir d’une zone de préparation </samples/clean-rooms/udf_from_stage.ipynb>. Exécutez ce notebook après avoir exécuté l’exemple du fournisseur pour essayer de charger une UDF à partir d’une zone de préparation.

  • :download :Chargement de plusieurs fonctions Python dans un seul correctif. </samples/clean-rooms/upload-multiple-python-packages.sql> Il s’agit d’une salle blanche de test interne à compte unique ; vous pouvez utiliser le même compte pour le rôle de fournisseur et le rôle de consommateur.

Code soumis par le consommateur

Le code chargé par le consommateur est regroupé et importé avec un modèle personnalisé à l’aide du flux de chargement du modèle du consommateur. Le code chargé peut être appelé par n’importe quel modèle dans la salle blanche.

Pour charger du code en tant que consommateur, vous devez comprendre la syntaxe des modèles personnalisés.

Notez que tout code chargé par un consommateur peut être vu par le fournisseur lorsqu’il demande l’autorisation de l’importer. Le code du consommateur est également visible chaque fois qu’un fournisseur ou un consommateur examine le modèle.

Voici un aperçu des étapes à suivre pour charger un code consommateur personnalisé :

  1. Le fournisseur crée la salle blanche de la manière standard, puis invite le consommateur.

  2. Le consommateur installe et configure la salle blanche de la manière standard.

  3. Le consommateur prépare un modèle qui appelle l’UDF ou l’UDTF dans l’espace de noms de la cleanroom. Par exemple, pour appeler la fonction calculate_tax définie par le consommateur, un modèle simple peut ressembler à l’extrait suivant :

    SELECT {{ cleanroom.calculate_tax(p.cost) }} AS Tax FROM my_db.my_sch.sales AS p;
    
    Copy
  4. Le consommateur prépare son code Python. Nous vous recommandons d’utiliser des guillemets doubles (" ") plutôt que des guillemets simples (' ') dans votre code afin d’éviter tout échappement supplémentaire nécessaire ultérieurement. Votre code peut faire référence à ces bibliothèques Python prises en charge.

  5. Le consommateur transmet son code Python à consumer.generate_python_request_template. La procédure renvoie le code Python sous forme de procédure stockée, avec un espace réservé pour le modèle JinjaSQL personnalisé. Il existe plusieurs chaînes de plusieurs lignes dans le modèle qui utilisent $$ en tant que délimiteurs à plusieurs lignes.

  6. Le consommateur remplace l’espace réservé du modèle dans la sortie de generate_python_request_template par son modèle JinjaSQL.

  7. Dans le modèle combiné, échappez les guillemets simples comme suit : \'. En effet, les guillemets simples seront utilisés comme délimiteurs externes pour toute la chaîne de procédure multiligne quand vous le chargez dans la salle blanche. Voici un exemple de procédure stockée qui inclut le code Python du consommateur et le modèle personnalisé, avec l’échappement des caractères :

      BEGIN
    
      CREATE OR REPLACE FUNCTION CLEANROOM.custom_compare(min_status STRING, max_status STRING, this_status STRING)
      RETURNS boolean
      LANGUAGE PYTHON
      RUNTIME_VERSION = 3.10
      PACKAGES = (\'numpy\')
    
      HANDLER = \'custom_compare\'
      AS $$
      import numpy as np
    
      def custom_compare(min_status:str, max_status:str, this_status:str):
        statuses = [\'MEMBER\', \'SILVER\', \'GOLD\', \'PLATINUM\']
        return ((statuses.index(this_status) >= statuses.index(min_status)) &
                (statuses.index(this_status) <= statuses.index(max_status)))
      $$;
    
      -- Custom template
      LET SQL_TEXT varchar := $$
      SELECT
        c.status,
        c.hashed_email
      FROM IDENTIFIER( {{ my_table[0] }} ) as c
      WHERE cleanroom.custom_compare({{ min_status }}, {{ max_status }}, c.status);
      $$;
    
      LET RES resultset := (EXECUTE IMMEDIATE :SQL_TEXT);
      RETURN TABLE(RES);
    
      END;
    
    Copy
  8. Le consommateur appelle consumer.create_template_request avec le modèle combiné. Utilisez des guillemets simples (' ') au lieu de délimiteurs à double signe de dollar ($$...$$) autour du code que vous fournissez pour la procédure stockée dans l’argument template_definition. Par exemple :

    CALL samooha_by_snowflake_local_db.consumer.create_template_request(
      $cleanroom_name,
      $template_name,
      '
    BEGIN
    
    -- First, define the Python UDF.
    CREATE OR REPLACE FUNCTION CLEANROOM.custom_compare(min_status STRING, max_status STRING, this_status STRING)
    RETURNS boolean
    LANGUAGE PYTHON
    RUNTIME_VERSION = 3.10
    PACKAGES = (\'numpy\')
    
    HANDLER = \'custom_compare\'
    AS $$
    import numpy as np
    
    def custom_compare(min_status:str, max_status:str, this_status:str):
      statuses = [\'MEMBER\', \'SILVER\', \'GOLD\', \'PLATINUM\']
      return ((statuses.index(this_status) >= statuses.index(min_status)) &
              (statuses.index(this_status) <= statuses.index(max_status)))
        $$;
    
    -- Then define and execute the SQL query.
    LET SQL_TEXT varchar := $$
    SELECT
      c.status,
      c.hashed_email
    FROM IDENTIFIER( {{ my_table[0] }} ) as c
    WHERE cleanroom.custom_compare({{ min_status }}, {{ max_status }}, c.status);
    $$;
    
    -- Execute the query and then return the result.
    LET RES resultset := (EXECUTE IMMEDIATE :SQL_TEXT);
    RETURN TABLE(RES);
    
    END;
    ');
    
    Copy
  9. Le consommateur et le fournisseur poursuivent avec le flux de modèles défini par le consommateur :

    1. Le fournisseur voit la requête de modèle (provider.list_pending_template_requests) et l’approuve ensuite en appelant approve_template_request. Dans la requête, le fournisseur peut voir le modèle et le code en bundle.

    2. Le consommateur vérifie le statut de la requête (consumer.list_template_requests), et lorsque le statut est APPROVED, il exécute le modèle (consumer.run_analysis).

Exemples de code écrit par les consommateurs

Les exemples suivants illustrent l’ajout d’UDFs écrites par le fournisseur dans une salle blanche.

Téléchargez les exemples suivants, puis chargez-les sous forme de fichiers de feuilles de calcul dans votre compte Snowflake. Vous avez besoin de comptes distincts pour le fournisseur et le consommateur, chacun avec l’API de salles blanches installée. Remplacez les informations comme indiqué dans les fichiers d’exemple :

  • :download :Exemple de code fournisseur</samples/clean-rooms/consumer-udf-p.sql>

  • :download :Exemple de code consommateur</samples/clean-rooms/consumer-udf-c.sql>

  • :download :Code écrit par le consommateur et exécuté par le fournisseur : notebook du fournisseur</samples/clean-rooms/p-run-c-uploaded-code-p.sql>

  • :download :Code écrit par le consommateur et exécuté par le fournisseur : notebook du consommateur</samples/clean-rooms/p-run-c-uploaded-code-c.sql>