Résolution de noms

S’applique à :case marquée oui Databricks SQL case marquée oui Databricks Runtime

La résolution de noms est le processus par lequel les identificateurs sont résolus en références de colonne, de champ, de paramètre ou de table spécifiques.

Résolution de colonnes, champs, paramètres et variables

Les identificateurs contenus dans les expressions peuvent faire référence aux éléments suivants :

  • Nom de colonne basé sur une vue, une table, une expression de table commune (CTE) ou un alias de colonne.
  • Nom de champ ou clé de mappage dans un struct ou un mappage. Les champs et les clés ne peuvent jamais être non qualifiés.
  • Nom du paramètre d’une fonction définie par l’utilisateur SQL ou d’une procédure SQL.
  • Nom de variable locale de session ou de script SQL.
  • Fonction spéciale (par exemple current_user ou current_date) pour laquelle les parenthèses () ne sont pas nécessaires.
  • Le mot clé DEFAULT utilisé dans le contexte de INSERT, de UPDATE, de MERGE ou de SET VARIABLE pour définir une colonne ou une variable à sa valeur par défaut.

La résolution de noms applique les principes suivants :

  • La référence correspondante la plus proche gagne.
  • Les colonnes et les paramètres l’emportent sur les champs et les clés.

Dans le détail, la résolution des identificateurs en une référence spécifique suit les règles suivantes, dans l’ordre :

  1. Références locales

    1. Référence de colonne

      Faire correspondre l’identificateur, qui peut être qualifié, à un nom de colonne dans une référence de table de la clause FROM clause.

      S’il existe plusieurs correspondances de ce type, déclencher une erreur AMBIGUOUS_COLUMN_OR_FIELD.

    2. Référence de fonction sans paramètre

      Si l’identificateur n’est pas qualifié et correspond à current_user, à current_date ou à current_timestamp, le résoudre comme l’une de ces fonctions.

    3. Spécification DEFAULT de colonne

      Si l’identificateur n’est pas qualifié, correspond à default et compose la totalité de l’expression dans le contexte d’une instruction UPDATE SET, INSERT VALUES ou MERGE WHEN [NOT] MATCHED, le résoudre comme la valeur DEFAULT associée de la table cible de l’instruction INSERT, UPDATE ou MERGE.

    4. Référence de champ de struct ou de clé de mappage

      Si l’identificateur est qualifié, tenter de le faire correspondre à un champ ou à une clé de mappage en procédant comme suit :

      R. Supprimer le dernier identificateur et le traiter comme un champ ou une clé. B. Faire correspondre le reste à une colonne dans la référence de table de la clause FROM clause.

      S’il existe plusieurs correspondances de ce type, déclencher une erreur AMBIGUOUS_COLUMN_OR_FIELD.

      S’il existe une correspondance, la résolution dépend de la nature de la colonne :

      • STRUCT : correspond au champ.

        S’il n’est pas possible de faire correspondre le champ, déclencher une erreur FIELD_NOT_FOUND.

        S’il existe plusieurs champs, déclencher une erreur AMBIGUOUS_COLUMN_OR_FIELD.

      • MAP : déclencher une erreur si la clé est qualifiée.

        Une erreur d’exécution peut se produire si la clé n’est pas réellement présente dans la carte.

      • Tout autre type : déclencher une erreur. Chapitre C. Répéter l’étape précédente pour supprimer le champ d’identificateur de fin. Appliquer les règles A et B lorsqu’il reste un identificateur à interpréter comme colonne.

  2. Création d’un alias de colonne latérale

    S’applique à :coche marquée oui Databricks SQL oui coché Databricks Runtime 12.2 LTS et versions ultérieures

    Si l’expression se trouve dans une liste SELECT, faire correspondre l’identificateur de début à un alias de colonne précédent dans cette liste SELECT.

    S’il existe plusieurs correspondances de ce type, déclencher une erreur AMBIGUOUS_LATERAL_COLUMN_ALIAS.

    Faire correspondre chaque identificateur restant comme champ ou clé de mappage et, si ce n’est pas possible, déclencher une erreur FIELD_NOT_FOUND ou AMBIGUOUS_COLUMN_OR_FIELD.

  3. Corrélation

    • LATÉRALE

      Si la requête est précédée d’un mot clé LATERAL, appliquer les règles 1.a et 1.d en tenant compte des références de table de la clause FROM contenant la requête et précédant le mot clé LATERAL.

    • Régulier

      Si la requête est une sous-requête scalaire, IN ou une sous-requête EXISTS, appliquez les règles 1.a, 1.d et 2 en tenant compte des références de table dans la clause FROM de la requête contenante.

  4. Corrélation imbriquée

    S’applique à :coché oui Databricks SQL coché oui Databricks Runtime 20.0 et supérieur

    Réappliquez la règle 3, en itérant sur les niveaux d’imbriquage de la requête, afin qu’un identifiant puisse résoudre une référence corrélée dans n’importe quelle requête d’enclos, et pas seulement celle qui enferme immédiatement.

  5. Boucle FOR

    Si l’instruction est contenue dans une FOR boucle :

    R. Faire correspondre l’identificateur à une colonne dans une requête d’instruction FOR de boucle. Si l’identificateur est qualifié, le qualificateur doit correspondre au nom de la variable de boucle FOR s’il est défini. B. Si l’identificateur est qualifié, le faire correspondre à un champ ou à une clé de mappage d’un paramètre suivant la règle 1.c.

  6. Instruction composée

    Si l’instruction est contenue dans une instruction composée :

    R. Faire correspondre l’identificateur à une variable déclarée dans cette instruction composée. Si l’identificateur est qualifié, le qualificateur doit correspondre à l’étiquette de l’instruction composée si un identificateur a été défini. B. Si l’identificateur est qualifié, le faire correspondre à un champ ou à la clé de mappage d’une variable suivant la règle 1.c

  7. Instruction imbriquée composée ou FOR boucle

    Réappliquez les règles 5 et 6, en itérant sur les niveaux d’imbrication de la déclaration composée.

  8. Paramètres de routine

    Si l’expression fait partie d’une instruction CREATE FUNCTIONCREATE PROCEDURE :

    1. Faire correspondre l’identificateur à un nom de paramètre. Si l’identificateur est qualifié, le qualificateur doit correspondre au nom de la routine.
    2. Si l’identificateur est qualifié, le faire correspondre à un champ ou à une clé de mappage d’un paramètre suivant la règle 1.c.
  9. Session Variables

    1. Faire correspondre l’identificateur à un nom de variable. Si l’identificateur est qualifié, il doit être session ou system.session. Dans Databricks SQL et Databricks Runtime 19 et supérieur, un identifiant non qualifié correspond à une variable de session uniquement si system.session se trouve sur le PATH.
    2. Si l’identificateur est qualifié, le faire correspondre à un champ ou à la clé de mappage d’une variable suivant la règle 1.c

Résolution de noms dans HAVING, ORDER BYet QUALIFY

Les HAVINGclauses , et ORDER BY les clauses QUALIFYpeuvent référencer des noms à partir de la SELECT liste ainsi que des colonnes des tables sous-jacentes. Lorsqu’un nom dans l’une de ces clauses correspond à la fois à un alias de colonne dans la SELECT liste et à une colonne de table, les clauses résolvent l’ambiguïté différemment :

  • ORDER BYpréfère l’alias deSELECT liste sur la colonne de table.
  • HAVING préfère la colonne de table sur l’alias de SELECT liste.
  • QUALIFY préfère la colonne de table sur l’alias de SELECT liste (identique à HAVING).

Exemples

> CREATE OR REPLACE TEMPORARY VIEW t(a, b) AS VALUES (1, 10), (2, 20), (3, 30);

-- ORDER BY prefers the alias over the column.
-- 'a' in ORDER BY refers to the alias (-a), not column 'a',
-- so the row with the largest column 'a' comes first.
> SELECT -a AS a FROM t ORDER BY a LIMIT 1;
  -3

-- HAVING prefers the column over the alias.
-- 'a' in HAVING refers to column 'a', not the alias sum(b).
> SELECT sum(b) AS a FROM t GROUP BY a HAVING a > 1;
  20
  30

-- QUALIFY prefers the column over the alias (same as HAVING).
-- 'a' in QUALIFY refers to column 'a', not the alias -row_number().
> SELECT -row_number() OVER (ORDER BY b) AS a FROM t QUALIFY a > 1;
  -2
  -3

Priorité d’extraction de champs et de résolution de noms

Lorsqu’un nom qualifié tel qu’il a.b est utilisé ou HAVINGORDER BYque les règles de priorité ci-dessus s’appliquent toujours, mais avec une considération supplémentaire : le candidat préféré doit prendre en charge le champ de struct ou l’extraction de clé de carte. Si ce n’est pas le cas, l’autre candidat est utilisé à la place.

Par exemple, si l’alias a se résout en une simple INT , mais que la colonne a de table est un STRUCT champ avec un champ x, ORDER BY choisit la STRUCT colonne, car un champ ne peut pas être extrait de l’alias INT . À l’inverse, si la colonne de table est simple INT et que l’alias est un STRUCT, HAVING revient à l’alias pour l’extraction de champ.

Exemples

-- ORDER BY fallback: the table column is a STRUCT, the alias is an INT.
-- ORDER BY normally prefers the alias, but the alias (INT) cannot have
-- field 'x' extracted, so the struct column wins.
> CREATE OR REPLACE TEMPORARY VIEW s1(a) AS VALUES (named_struct('x', 1)), (named_struct('x', 2));

> SELECT -a.x AS a FROM s1 ORDER BY a.x LIMIT 1;
  -1

-- HAVING fallback: the table column is an INT, the alias is a STRUCT.
-- HAVING normally prefers the table column, but the column (INT) cannot have
-- field 'x' extracted, so the alias wins.
> CREATE OR REPLACE TEMPORARY VIEW s2(a) AS VALUES (1), (2);

> SELECT named_struct('x', 2) AS a FROM s2 GROUP BY a HAVING a.x > 1;
  {"x":2}
  {"x":2}

-- Map key extraction follows the same rules.
-- ORDER BY fallback: alias (INT) cannot have key extracted, map column wins.
> CREATE OR REPLACE TEMPORARY VIEW s3(a) AS VALUES (map('key', 100)), (map('key', 200));

> SELECT -a['key'] AS a FROM s3 ORDER BY a['key'] LIMIT 1;
  -100

-- HAVING fallback: column (INT) cannot have key extracted, map alias wins.
> CREATE OR REPLACE TEMPORARY VIEW s4(a) AS VALUES (100), (200);

> SELECT map('key', 200) AS a FROM s4 GROUP BY a HAVING a['key'] > 100;
  {"key":200}
  {"key":200}

Limites

Dans Databricks SQL et Databricks Runtime 20.0 et supérieur, la corrélation imbriquée (une sous-requête qui fait référence aux colonnes d’une requête annexe au-delà de son parent immédiat) est prise en charge, avec les limitations suivantes :

  • La corrélation imbriquée n’est pas prise en charge pour les sous-requêtes d’une HAVING clause.
  • Une LATERAL sous-requête ne peut pas être imbriquée-corrélée. Ses références externes doivent se résoudre à la requête directement jointe.

Dans les versions Databricks Runtime inférieures à la 20.0, la corrélation est limitée à un seul niveau : une sous-requête ne peut référencer que les colonnes de la requête qui l’enferme immédiatement.

Exemples

-- Differentiating columns and fields
> SELECT a FROM VALUES(1) AS t(a);
 1

> SELECT t.a FROM VALUES(1) AS t(a);
 1

> SELECT t.a FROM VALUES(named_struct('a', 1)) AS t(t);
 1

-- A column takes precedence over a field
> SELECT t.a FROM VALUES(named_struct('a', 1), 2) AS t(t, a);
 2

-- Implict lateral column alias
> SELECT c1 AS a, a + c1 FROM VALUES(2) AS T(c1);
 2  4

-- A local column reference takes precedence, over a lateral column alias
> SELECT c1 AS a, a + c1 FROM VALUES(2, 3) AS T(c1, a);
 2  5

-- A scalar subquery correlation to S.c3
> SELECT (SELECT c1 FROM VALUES(1, 2) AS t(c1, c2)
           WHERE t.c2 * 2 = c3)
    FROM VALUES(4) AS s(c3);
 1

-- A local reference takes precedence over correlation
> SELECT (SELECT c1 FROM VALUES(1, 2, 2) AS t(c1, c2, c3)
           WHERE t.c2 * 2 = c3)
    FROM VALUES(4) AS s(c3);
  NULL

-- An explicit scalar subquery correlation to s.c3
> SELECT (SELECT c1 FROM VALUES(1, 2, 2) AS t(c1, c2, c3)
           WHERE t.c2 * 2 = s.c3)
    FROM VALUES(4) AS s(c3);
 1

-- Correlation from an EXISTS predicate to t.c2
> SELECT c1 FROM VALUES(1, 2) AS T(c1, c2)
    WHERE EXISTS(SELECT 1 FROM VALUES(2) AS S(c2)
                  WHERE S.c2 = T.c2);
 1

-- Nested correlation: the innermost EXISTS references t1.a from the outermost query
> CREATE OR REPLACE TEMPORARY VIEW t1(a) AS VALUES(1), (2), (3);
> CREATE OR REPLACE TEMPORARY VIEW t2(b) AS VALUES(1), (2);
> CREATE OR REPLACE TEMPORARY VIEW t3(c) AS VALUES(2), (3);

> SELECT a FROM t1
    WHERE EXISTS(SELECT 1 FROM t2
                  WHERE t2.b = t1.a
                    AND EXISTS(SELECT 1 FROM t3
                                WHERE t3.c = t1.a));
 2

-- Attempt a lateral correlation to t.c2
> SELECT c1, c2, c3
    FROM VALUES(1, 2) AS t(c1, c2),
         (SELECT c3 FROM VALUES(3, 4) AS s(c3, c4)
           WHERE c4 = c2 * 2);
 [UNRESOLVED_COLUMN] `c2`

-- Successsful usage of lateral correlation with keyword LATERAL
> SELECT c1, c2, c3
    FROM VALUES(1, 2) AS t(c1, c2),
         LATERAL(SELECT c3 FROM VALUES(3, 4) AS s(c3, c4)
                  WHERE c4 = c2 * 2);
 1  2  3

-- Referencing a parameter of a SQL function
> CREATE OR REPLACE TEMPORARY FUNCTION func(a INT) RETURNS INT
    RETURN (SELECT c1 FROM VALUES(1) AS T(c1) WHERE c1 = a);
> SELECT func(1), func(2);
 1  NULL

-- A column takes precedence over a parameter
> CREATE OR REPLACE TEMPORARY FUNCTION func(a INT) RETURNS INT
    RETURN (SELECT a FROM VALUES(1) AS T(a) WHERE t.a = a);
> SELECT func(1), func(2);
 1  1

-- Qualify the parameter with the function name
> CREATE OR REPLACE TEMPORARY FUNCTION func(a INT) RETURNS INT
    RETURN (SELECT a FROM VALUES(1) AS T(a) WHERE t.a = func.a);
> SELECT func(1), func(2);
 1  NULL

-- Lateral alias takes precedence over correlated reference
> SELECT (SELECT c2 FROM (SELECT 1 AS c1, c1 AS c2) WHERE c2 > 5)
    FROM VALUES(6) AS t(c1)
  NULL

-- Lateral alias takes precedence over function parameters
> CREATE OR REPLACE TEMPORARY FUNCTION func(x INT)
    RETURNS TABLE (a INT, b INT, c DOUBLE)
    RETURN SELECT x + 1 AS x, x
> SELECT * FROM func(1)
  2 2

-- All together now
> CREATE OR REPLACE TEMPORARY VIEW lat(a, b) AS VALUES('lat.a', 'lat.b');

> CREATE OR REPLACE TEMPORARY VIEW frm(a) AS VALUES('frm.a');

> CREATE OR REPLACE TEMPORARY FUNCTION func(a INT, b int, c int)
  RETURNS TABLE
  RETURN SELECT t.*
    FROM lat,
         LATERAL(SELECT a, b, c
                   FROM frm) AS t;

> VALUES func('func.a', 'func.b', 'func.c');
  a      b      c
  -----  -----  ------
  frm.a  lat.b  func.c

Résolution de table et de vue

Un identificateur contenu dans une référence de table peut correspondre à l’un des éléments suivants :

  • Table ou vue persistante dans Unity Catalog ou le metastore Hive
  • Expression de table commune (CTE)
  • Vue temporaire ou table temporaire

La résolution d’un identificateur dépend de son caractère qualifié ou non :

  • Qualifié

    Si l’identificateur est complet et comporte trois parties catalog.schema.relation, il est unique.

    Si l’identificateur se compose de deux parties schema.relation, il est qualifié davantage avec le résultat de l’instruction SELECT current_catalog() de façon à devenir unique.

    Si le schéma est session, il est en outre qualifié et system interprété comme une vue temporaire ou une table temporaire. Si le schéma est global_temp, il est également qualifié et system interprété comme une vue temporaire globale dans Databricks Runtime.

  • Non qualifié

    1. Expression commune de table

      Si la référence se trouve dans l’étendue d’une clause WITH, faire correspondre l’identificateur à une expression de table commune en commençant par la clause WITH directement englobante et en se déplaçant vers l’extérieur.

    2. Chemin de recherche de schéma

      Dans Databricks SQL et Databricks Runtime 19 et supérieur, qualifiez la relation avec chaque schéma sur le PATH, dans l’ordre, jusqu’à ce qu’une correspondance soit trouvée.

      • Catalogues ou schémas manquants : Les catalogues ou schémas manquants sur le chemin sont sautés. Un objet pour lequel l’utilisateur dispose de privilèges insuffisants n’est pas sauté ; Azure Databricks génère l’erreur correspondante.
      • Vues et tableaux temporaires : Les vues temporaires et les tables temporaires vivent dans system.session, donc elles sont accessibles dès que system.session c’est sur le PATH.
      • Tables et vues persistantes dans le schéma actuel : Les tables persistantes et les vues dans le schéma actuel sont accessibles via l’entrée virtuelle CURRENT_SCHEMA .

      Le chemin s’applique aux noms de relations non qualifiées dans les requêtes et les DML, ainsi qu’aux noms non qualifiés dans une requête faisant partie d’une instruction DDL.

      • Où le chemin s’applique :

        Context Chemin utilisé
        Requêtes et DML (SELECT, INSERT, UPDATE, DELETE, MERGE) Chemin de session
        Requête de l’ASCREATE TABLE Chemin de session
        Requête d’un persistant CREATE VIEW PATH capturé au moment de la création
        Sujet de CREATE, DROP, ALTER, et similaires current_catalog.current_schema (pas une recherche de chemin)
      • Versions antérieures : Dans Databricks Runtime 18 et inférieurs, une relation non qualifiée qui n’est pas une CTE est résolue dans un ordre fixe.

        1. Vue temporaire ou table temporaire

          Faire correspondre l’identificateur à toute vue temporaire ou table temporaire définie dans la session active.

        2. Table persistante

          Qualifier entièrement l’identificateur en le faisant précéder du résultat de SELECT current_catalog() et de SELECT current_schema() et le rechercher comme une relation persistante.

S’il n’est pas possible de résoudre la relation en une table, une vue ni une expression de table commune, Databricks génère une erreur TABLE_OR_VIEW_NOT_FOUND.

Chemin capturé

Une vue persistante capture le PATH de la session au moment de la création. Les requêtes ultérieures de la vue résolvent des noms non qualifiés contre ce chemin capturé, et non sur le chemin de session de l’invokateur. current_path() et current_schema() dans cette requête, il reste de retourner les valeurs de session de l’invocateur.

Exemples

-- Setting up a scenario
> USE CATALOG spark_catalog;
> USE SCHEMA default;

> CREATE TABLE rel(c1 int);
> INSERT INTO rel VALUES(1);

-- An fully qualified reference to rel:
> SELECT c1 FROM spark_catalog.default.rel;
 1

-- A partially qualified reference to rel:
> SELECT c1 FROM default.rel;
 1

-- An unqualified reference to rel:
> SELECT c1 FROM rel;
 1

-- Add a temporary view with a conflicting name:
> CREATE TEMPORARY VIEW rel(c1) AS VALUES(2);

-- For unqualified references the temporary view takes precedence over the persisted table:
> SELECT c1 FROM rel;
 2

-- Temporary views cannot be qualified, so qualifiecation resolved to the table:
> SELECT c1 FROM default.rel;
 1

-- An unqualified reference to a common table expression wins even over a temporary view:
> WITH rel(c1) AS (VALUES(3))
    SELECT * FROM rel;
 3

-- If CTEs are nested, the match nearest to the table reference takes precedence.
> WITH rel(c1) AS (VALUES(3))
    (WITH rel(c1) AS (VALUES(4))
      SELECT * FROM rel);
  4

-- To resolve the table instead of the CTE, qualify it:
> WITH rel(c1) AS (VALUES(3))
    (WITH rel(c1) AS (VALUES(4))
      SELECT * FROM default.rel);
  1

-- For a CTE to be visible it must contain the query
> SELECT * FROM (WITH cte(c1) AS (VALUES(1))
                   SELECT 1),
                cte;
  [TABLE_OR_VIEW_NOT_FOUND] The table or view `cte` cannot be found.

Résolution de fonctions et de procédures

Une référence de routine (un appel de fonction ou d’appel de procédure) est reconnue par l’ensemble obligatoire de parenthèses de suite.

Elle peut se résoudre en différents types de fonctions :

La résolution d’un nom de routine dépend de sa qualification ou non :

  • Qualifié

    Si le nom est complet et comporte trois parties catalog.schema.routine, il est unique.

    Si le nom se compose de deux parties schema.routine, il est qualifié davantage avec le résultat de l’instruction SELECT current_catalog() de façon à devenir unique.

    Si le schéma est session, il est en outre qualifié et system interprété comme une fonction temporaire.

    La routine est ensuite consultée dans le catalogue.

  • Non qualifié

    • Chemin de recherche de schéma : Dans Databricks SQL et Databricks Runtime 19 et supérieur, qualifiez le nom de routine avec chaque schéma sur le PATH dans l’ordre et choisissez la première correspondance.
    • Catalogues ou schémas manquants : Les catalogues ou schémas manquants sur le chemin sont sautés. Un objet pour lequel l’utilisateur dispose de privilèges insuffisants n’est pas sauté ; Azure Databricks génère l’erreur correspondante.
    • Là où se trouvent les routines : Les fonctions scalaires et de table intégrées sont dans system.builtin, les fonctions IA dans system.ai, et les fonctions temporaires dans system.session.
    • Chemin par défaut : Le chemin par défaut PATH est system.session, puis system.builtin, system.aipuis CURRENT_SCHEMA.

    Warning

    Les fonctions temporaires du même nom que les fonctions intégrées ont la priorité car system.session elles sont précédées system.builtin sur le chemin par défaut. Vous pouvez réorganiser le chemin avec SET PATH. Ne comptez pas sur des fonctions temporaires qui font de l’ombrage pour les fonctions intégrées.

    • Où le chemin s’applique :

      Context Chemin utilisé
      Noms de routines non qualifiés dans les requêtes et les DML Chemin de session
      Corps d’une fonction SQL définie par l’utilisateur PATH capturé au moment de la création
      Corps d’une SQL SECURITY DEFINER procédure PATH capturé au moment de la création, sans system.session
      Corps d’une SQL SECURITY INVOKER procédure Chemin en direct de l’appelant
      Sujet de CREATE FUNCTION, DROP FUNCTION, CREATE PROCEDURE, et similaires Schéma actuel (pas une recherche de chemin)
    • Versions antérieures : Dans Databricks Runtime 18 et inférieurs, Azure Databricks suit un ordre de préséance fixe.

      1. Fonction intégrée

        Si une fonction de ce nom existe parmi l’ensemble de fonctions intégrées, choisir cette fonction.

      2. Fonction temporaire

        Si une fonction de ce nom existe parmi l’ensemble de fonctions temporaires, choisir cette fonction.

      3. Fonction persistante

        Qualifier entièrement le nom de fonction en le faisant précéder du résultat de SELECT current_catalog() et de SELECT current_schema() et le rechercher comme une fonction persistante.

Si la routine ne peut pas être résolue, Azure Databricks génère une UNRESOLVED_ROUTINE erreur.

Chemin capturé

  • Fonction définie par l’utilisateur SQL : Les noms non qualifiés dans le corps sont résolus par rapport au PATH capturé à CREATE FUNCTION, et non au chemin de session de l’invokateur. current_path() et current_schema() dans ce corps renvoient toujours les valeurs de la session de l’invokateur.
  • Procédure avec SQL SECURITY DEFINER: Les noms non qualifiés sont résolus contre le PATH capturé dans la PROCÉDURE CREATE, avec system.session omission. current_path() dans ce corps, ce même chemin capturé revient.
  • Procédure avec SQL SECURITY INVOKER: Les noms non qualifiés utilisent le chemin en direct de l’appelant.

Exemples

> USE CATALOG spark_catalog;
> USE SCHEMA default;

-- Create a function with the same name as a builtin
> CREATE FUNCTION concat(a STRING, b STRING) RETURNS STRING
    RETURN b || a;

-- unqualified reference resolves to the builtin CONCAT
> SELECT concat('hello', 'world');
 helloworld

-- Qualified reference resolves to the persistent function
> SELECT default.concat('hello', 'world');
 worldhello

-- Create a persistent function
> CREATE FUNCTION func(a INT, b INT) RETURNS INT
    RETURN a + b;

-- The persistent function is resolved without qualifying it
> SELECT func(4, 2);
 6

-- Create a conflicting temporary function
> CREATE FUNCTION func(a INT, b INT) RETURNS INT
    RETURN a / b;

-- The temporary function takes precedent
> SELECT func(4, 2);
 2

-- To resolve the persistent function it now needs qualification
> SELECT spark_catalog.default.func(4, 3);
 6