Risoluzione dei nomi

Si applica a:segno di spunta sì Databricks SQL segno di spunta sì Databricks Runtime

La risoluzione dei nomi è il processo attraverso cui identificatori vengono risolti in riferimenti specifici a colonne, campi, parametri o tabelle.

Risoluzione di colonne, campi, parametri e variabili

Gli identificatori nelle espressioni possono essere riferimenti a uno dei seguenti elementi:

  • Nome colonna in base a una vista, una tabella, un'espressione di tabella comune (CTE) o un column_alias.
  • Nome del campo o chiave della mappa all'interno di uno struct o di una mappa. I campi e le chiavi non possono mai essere non qualificati.
  • Nome del parametro di una funzione definita dall'utente SQL o di una routine SQL.
  • Il nome della variabile locale di sessione o SQL .
  • Una funzione speciale, current_user ad esempio o current_date che non richiede l'utilizzo di ().
  • La parola chiave DEFAULT usata nel contesto di INSERT, UPDATE, MERGEo SET VARIABLE per impostare il valore di una colonna o di una variabile al valore predefinito.

La risoluzione dei nomi applica i principi seguenti:

  • Il riferimento corrispondente più vicino vince e
  • Colonne e parametri vincono campi e chiavi.

In dettaglio, la risoluzione degli identificatori a un riferimento specifico segue queste regole nell'ordine seguente:

  1. Riferimenti locali

    1. riferimento alla colonna

      Trovare la corrispondenza dell'identificatore, che può essere qualificato, con un nome di colonna in riferimento alla tabella del FROM clause.

      Se sono presenti più corrispondenze di questo tipo, generare un errore di AMBIGUOUS_COLUMN_OR_FIELD .

    2. Informazioni di riferimento sulle funzioni senza parametri

      Se l'identificatore non è qualificato e corrisponde a current_user, current_dateo current_timestamp: risolverlo come una di queste funzioni.

    3. specifica colonna DEFAULT

      Se l'identificatore non è qualificato, corrisponde a default e costituisce l'intera espressione nel contesto di un UPDATE SET, INSERT VALUESo MERGE WHEN [NOT] MATCHED: Risolvere come il rispettivo valore DEFAULT della tabella destinata a INSERT, UPDATE o MERGE.

    4. Riferimento al campo di struttura o alla chiave della mappa

      Se l'identificatore è qualificato, si dovrebbe cercare di associarlo a un campo o a una chiave di mappa in base ai passaggi seguenti:

      Un. Rimuovere l'ultimo identificatore e considerarlo come campo o chiave. B. Trova la corrispondenza tra il resto e una colonna nella tabella , riferimento del FROM clause.

      Se sono presenti più corrispondenze di questo tipo, generare un errore di AMBIGUOUS_COLUMN_OR_FIELD .

      Se esiste una corrispondenza e la colonna è un:

      • STRUCT: trova la corrispondenza con il campo.

        Se il campo non può essere corrisposto, viene generato un errore di FIELD_NOT_FOUND.

        Se sono presenti più campi, generare un errore di AMBIGUOUS_COLUMN_OR_FIELD .

      • MAP: genera un errore se la chiave è qualificata.

        Un errore di runtime può verificarsi se la chiave non è effettivamente presente nella mappa.

      • Qualsiasi altro tipo: generare un errore. C. Ripetere il passaggio precedente per rimuovere l'identificatore finale come un campo. Applicare regole (A) e (B) mentre è rimasto un identificatore da interpretare come colonna.

  2. aliasing delle colonne laterale

    Si applica a:segno di spunta sì Databricks SQL segno di spunta sì Databricks Runtime 12.2 LTS e versioni successive

    Se l'espressione si trova all'interno di un elenco , associa l'identificatore iniziale a un alias di colonna precedente in tale elenco .

    Se sono presenti più corrispondenze di questo tipo, generare un errore di AMBIGUOUS_LATERAL_COLUMN_ALIAS .

    Trova la corrispondenza di ogni identificatore rimanente come campo o chiave della mappa e genera un errore FIELD_NOT_FOUND o AMBIGUOUS_COLUMN_OR_FIELD se non possono essere abbinati.

  3. Correlazione

    • LATERALE

      Se la query è preceduta da una parola chiave LATERAL, applicare le regole 1.a e 1.d considerando i riferimenti alla tabella nel FROM contenente la query e precedente al LATERAL.

    • Regolare

      Se la query è una sottoquery scalare, INo EXISTS sottoquery, applicare le regole 1.a, 1.d e 2 considerando i riferimenti alla tabella nella clausola della query che lo contiene.

  4. Correlazione annidata

    Si applica a:spuntato sì Databrick SQL spuntato sì Databricks Runtime 20.0 e superiori

    Riapplica la regola 3, iterando sui livelli di annidamento della query, così che un identificatore possa risolversi in un riferimento correlato in qualsiasi query che lo includa, non solo in quella che lo racchiude immediatamente.

  5. Ciclo FOR

    Se l'istruzione è contenuta in un ciclo FOR:

    Un. Associare l'identificatore a una colonna in una query di un'istruzione di ciclo FOR. Se l'identificatore è qualificato, il qualificatore deve corrispondere al nome della variabile ciclo FOR, se definita. B. Se l'identificatore è qualificato, trovare la corrispondenza con un campo o una chiave della mappa di un parametro che segue la regola 1.c

  6. 'istruzione composta

    Se l'istruzione è contenuta in un'istruzione composta:

    Un. Associare l'identificatore a una variabile dichiarata nell'istruzione composta. Se l'identificatore è qualificato, il qualificatore deve corrispondere all'etichetta dell'istruzione composta se ne è stata definita una. B. Se l'identificatore è qualificato, trovare la corrispondenza con un campo o una chiave della mappa di una variabile che segue la regola 1.c

  7. istruzione composta annidata o FOR ciclo

    Applicare di nuovo le regole 5 e 6, iterando sui livelli di annidamento della dichiarazione composta.

  8. i parametri della routine

    Se l'espressione fa parte di un'istruzione CREATE FUNCTION o CREATE PROCEDURE:

    1. Associare l'identificatore a un nome di parametro . Se l'identificatore è qualificato, il qualificatore deve corrispondere al nome della routine.
    2. Se l'identificatore è qualificato, trovare la corrispondenza con un campo o una chiave della mappa di un parametro che segue la regola 1.c
  9. variabili di sessione

    1. Associare l'identificatore a un nome di variabile . Se l'identificatore è qualificato, il qualificatore deve essere session o system.session. In Databricks SQL e Databricks Runtime 19 e superiori, un identificatore non qualificato corrisponde a una variabile di sessione solo se system.session è sul PATH.
    2. Se l'identificatore è qualificato, trovare la corrispondenza con un campo o una chiave della mappa di una variabile che segue la regola 1.c

Risoluzione dei nomi in HAVING, ORDER BYe QUALIFY

Le HAVINGclausole , ORDER BYe QUALIFY possono fare riferimento ai nomi dall'elenco SELECT , nonché alle colonne delle tabelle sottostanti. Quando un nome in una di queste clausole corrisponde sia a un alias di colonna nell'elenco SELECT che a una colonna di tabella, le clausole risolvono l'ambiguità in modo diverso:

  • ORDER BYpreferisce l'alias dell'elencoSELECT rispetto alla colonna della tabella.
  • HAVING preferisce la colonna della tabella rispetto all'alias dell'elenco SELECT .
  • QUALIFY preferisce la colonna della tabella rispetto all'alias dell'elenco SELECT (uguale a HAVING).

Esempi

> 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

Estrazione dei campi e priorità di risoluzione dei nomi

Quando si usa un nome completo, ad a.b esempio in HAVING o ORDER BY, le regole di priorità precedenti si applicano ancora, ma con una considerazione aggiuntiva: il candidato preferito deve supportare l'estrazione di campi struct o chiavi della mappa. In caso contrario, viene usato l'altro candidato.

Ad esempio, se l'alias a viene risolto in una colonna normale INT ma la colonna a della tabella è un STRUCT con campo x, ORDER BY sceglie la STRUCT colonna perché non è possibile estrarre un campo dall'alias INT . Viceversa, se la colonna della tabella è normale INT e l'alias è , STRUCTHAVINGesegue il fallback all'alias per l'estrazione dei campi.

Esempi

-- 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}

Limiti

In Databricks SQL e Databricks Runtime 20.0 e superiori, è supportata la correlazione annidata (una sottoquery che fa riferimento alle colonne di una query che lo circonda oltre il suo genitore immediato), con le seguenti limitazioni:

  • La correlazione annidata non è supportata per le sottoquery in una HAVING clausola.
  • Una LATERAL sottoquery non può essere annidata e correlata (nested-correlate). I suoi riferimenti esterni devono risolversi alla query direttamente allegata.

Nelle versioni di Databricks Runtime inferiori alla 20.0, la correlazione è limitata a un singolo livello: una sottoquery può fare riferimento alle colonne solo della query che la racchiude immediatamente.

Esempi

-- 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

Risoluzione della tabella e della vista

Un identificatore nella tabella di riferimento può essere uno dei seguenti elementi:

  • Tabella o vista persistente nel Unity Catalog o nell'Hive Metastore
  • Espressione di tabella comune (CTE)
  • Vista temporanea o tabella temporanea

La risoluzione di un identificatore dipende dal fatto che sia qualificato:

  • Qualificato

    Se l'identificatore è completo con tre parti: catalog.schema.relation, è univoco.

    Se l'identificatore è costituito da due parti: schema.relation, è ulteriormente qualificato con il risultato di SELECT current_catalog() per renderlo univoco.

    Se lo schema è session, viene ulteriormente qualificato e system interpretato come una vista temporanea o una tabella temporanea. Se lo schema è global_temp, viene ulteriormente qualificato e system interpretato come una vista temporanea globale in Databricks Runtime.

  • Non qualificato

    1. Espressione di Tabella Comune

      Se il riferimento rientra nell'ambito di una clausola WITH, associare l'identificatore a un CTE, iniziando dalla clausola WITH che lo contiene immediatamente e proseguendo verso l'esterno.

    2. Percorso di ricerca dello schema

      In Databricks SQL e Databricks Runtime 19 e superiori, si qualifica la relazione con ciascun schema sul PATH, in ordine, fino a trovare una corrispondenza.

      • Cataloghi o schemi mancanti: I cataloghi o gli schemi mancanti sul percorso vengono saltati. Un oggetto per il quale l'utente ha privilegi insufficienti non viene saltato; Azure Databricks genera l'errore corrispondente.
      • Viste e tabelle temporanee: Le viste temporanee e le tabelle temporanee vivono in system.session, quindi sono raggiunte ogni volta system.session che è sul PATH.
      • Tabelle e viste persistenti nello schema corrente: Le tabelle e le viste persistenti nello schema corrente sono raggiungibili tramite la voce virtuale CURRENT_SCHEMA .

      Il percorso si applica ai nomi di relazioni non qualificate nelle query e nel DML, e ai nomi non qualificati in una query che fa parte di un'istruzione DDL.

      • Dove si applica il percorso:

        Contesto Percorso utilizzato
        Query e DML (SELECT, INSERT, UPDATE, DELETE, MERGE) Session PATH
        Interrogazione dell'ASCREATE TABLE Session PATH
        Interrogazione di un persistente CREATE VIEW PATH catturato al momento di creazione
        Soggetto di CREATE, DROP, ALTER, e simili current_catalog.current_schema (non una ricerca di percorso)
      • Versioni precedenti: In Databricks Runtime 18 e inferiori, una relazione non qualificata che non è un CTE viene risolta in ordine fisso.

        1. Vista temporanea o tabella temporanea

          Associare l'identificatore a qualsiasi vista temporanea o tabella temporanea definita all'interno della sessione corrente.

        2. Tabella persistente

          Qualificare completamente l'identificatore anteponendo il risultato di SELECT current_catalog() e SELECT current_schema() e cercarlo come relazione permanente.

Se la relazione non può essere risolta in alcuna tabella, vista o CTE, Databricks genera un errore di TABLE_OR_VIEW_NOT_FOUND.

Percorso catturato

Una vista persistente cattura il PERCORSO della sessione al momento della creazione. Le query successive della vista risolvono nomi non qualificati contro quel percorso catturato, non contro quello della sessione dell'invocatore. current_path() e current_schema() in quella query restituisci comunque i valori della sessione dell'invocatore.

Esempi

-- 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.

Funzione e risoluzione delle procedure

Un riferimento di routine (una chiamata di funzione o chiamata di procedura) è riconosciuta dal set obbligatorio di parentesi.

Può risolversi in:

  • Una funzione predefinita fornita da Azure Databricks,
  • Una funzione definita dall'utente temporanea con ambito alla sessione corrente o
  • Una funzione o procedura definita dall'utente persistente memorizzata nel Metastore Hive o nel Catalogo Unity.

La risoluzione di un nome di routine dipende dal fatto che sia qualificato:

  • Qualificato

    Se il nome è completo con tre parti: catalog.schema.routine, è univoco.

    Se il nome è costituito da due parti: schema.routine, è ulteriormente qualificato con il risultato di SELECT current_catalog() per renderlo univoco.

    Se lo schema è session, è ulteriormente qualificato con system e interpretato come una funzione temporanea.

    La routine viene poi consultata nel catalogo.

  • Non qualificato

    • Percorso di ricerca dello schema: In Databricks SQL e Databricks Runtime 19 e superiori, si qualifica il nome della routine con ogni schema sul PATH in ordine e scegli la prima corrispondenza.
    • Cataloghi o schemi mancanti: I cataloghi o gli schemi mancanti sul percorso vengono saltati. Un oggetto per il quale l'utente ha privilegi insufficienti non viene saltato; Azure Databricks genera l'errore corrispondente.
    • Dove vivono le routine: le funzioni scalari e di tabella integrate sono presenti in system.builtin, le funzioni AI in system.ai, e le funzioni temporanee in system.session.
    • Percorso predefinito: Il percorso predefinito PATH è system.session, allora system.builtin, poi system.aiCURRENT_SCHEMA.

    Avvertimento

    Le funzioni temporanee con lo stesso nome delle funzioni integrate hanno la precedenza perché system.session vengono precedute system.builtin sul percorso predefinito. Puoi riordinare il percorso con SET PATH. Non affidarti a funzioni temporanee che affidano le funzioni integrate.

    • Dove si applica il percorso:

      Contesto Percorso utilizzato
      Nomi di routine non qualificati nelle query e nel DML Session PATH
      Corpo di una funzione definita dall'utente di SQL PATH catturato al momento di creazione
      Corpo di una SQL SECURITY DEFINER procedura PATH catturato al momento della creazione, senza system.session
      Corpo di una SQL SECURITY INVOKER procedura PERCORSO in diretta del chiamante
      Soggetto di CREATE FUNCTION, DROP FUNCTION, CREATE PROCEDURE, e simili Schema attuale (non una ricerca di percorso)
    • Versioni precedenti: In Databricks Runtime 18 e inferiori, Azure Databricks segue un ordine di precedenza fisso.

      1. Funzione Builtin

        Se esiste una funzione con questo nome tra il set di funzioni predefinite, tale funzione viene scelta.

      2. Funzione temporanea

        Se esiste una funzione con questo nome tra il set di funzioni temporanee, tale funzione viene scelta.

      3. Funzione persistente

        Completare la qualificazione del nome della funzione anteponendo il risultato di SELECT current_catalog() e SELECT current_schema() e verificarlo come una funzione persistente.

Se la routine non può essere risolta, Azure Databricks genera un UNRESOLVED_ROUTINE errore.

Percorso catturato

  • Funzione definita dall'utente SQL: I nomi non qualificati nel corpo vengono risolti contro il PATH catturato in CREATE FUNCTION, non sul percorso sessione dell'invocatore. current_path() e current_schema() in quel corpo restituiscono comunque i valori della sessione dell'invocatore.
  • Procedura con SQL SECURITY DEFINER: I nomi non qualificati vengono risolti contro il PATH catturato in CREATE PROCEDURE, con system.session omissione. current_path() in quel corpo ritorna lo stesso percorso catturato.
  • Procedura con: SQL SECURITY INVOKERI nomi non qualificati utilizzano il percorso live del chiamante.

Esempi

> 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