L’operatore di assegnazione dimenticato “=” e il luogo comune “: =”

La documentazione per PL / pgSQL dice che la dichiarazione e l’assegnazione alle variabili è fatta con := . Ma un semplice, più breve e più moderno (vedi nota in calce) = sembra funzionare come previsto:

  CREATE OR REPLACE FUNCTION foo() RETURNS int AS $$ DECLARE i int; BEGIN i = 0; WHILE NOT i = 25 LOOP i = i + 1; i = i * i; END LOOP; RETURN i; END; $$ LANGUAGE plpgsql; > SELECT foo(); 25 

Si noti che Pl / pgSQL è in grado di distinguere chiaramente assegnazione e confronto come mostrato nella riga

  WHILE NOT i = 25 LOOP 

Quindi, le domande sono:

  • Non ho trovato qualche sezione nei documenti che menzionano e / o lo spiegano?
  • Ci sono conseguenze note usando = invece di := ?

Modifica / Nota:

Per favore prendi la parte “più moderna” con un occhiolino come in Una storia di linguaggi di programmazione breve, incompleta e molto grave :

1970 – Niklaus Wirth crea Pascal, un linguaggio procedurale. I critici denunciano immediatamente Pascal perché utilizza la syntax “x: = x + y” invece del più familiare tipo “x = x + y”. Questa critica accade nonostante il fatto che C non sia stato ancora inventato.

1972 – Dennis Ritchie inventa una potente arma che spara simultaneamente in avanti e all’indietro. Non soddisfatto del numero di morti e di manomissioni permanenti di quell’invenzione, inventa C e Unix.

Nel parser PL / PgSQL, l’operatore di assegnazione è definito come

 assign_operator : '=' | COLON_EQUALS ; 

Questa è una funzione legacy, presente nel codice sorgente dal 1998, quando è stata introdotta, come possiamo vedere nel repository Git PostgreSQL .

A partire dalla versione 9.4 è ufficialmente documentato .

Questa idiosincrasia – di avere due operatori per la stessa cosa – è stata sollevata nella lista utenti di pgsql, e alcune persone hanno chiesto che venisse rimossa, ma è ancora mantenuta nel nucleo perché il corpus equo del codice legacy si basa su di esso.

Vedi questo messaggio da Tom Lane (core Pg developer) .

Quindi, per rispondere alle tue domande direttamente:

Non ho trovato qualche sezione nei documenti che menzionano e / o lo spiegano?

Non l’hai trovato perché non era documentato, che è stato risolto a partire dalla versione 9.4.

Ci sono conseguenze note usando = invece di: =.

Non ci sono conseguenze secondarie dell’uso di = , ma dovresti usare : = per l’assegnazione per rendere il tuo codice più leggibile e (come effetto collaterale) più compatibile con PL / SQL.

Aggiornamento: potrebbe esserci una conseguenza secondaria in scenari rari (vedi la risposta di Erwin)


AGGIORNAMENTO: risposta aggiornata grazie all’input di Daniel, Sandy e altri.

Q1

Questo è stato finalmente aggiunto alla documentazione ufficiale con Postgres 9.4 :

Un’assegnazione di un valore a una variabile PL / pgSQL è scritta come:

variable { := | = } expression;

[…] È ansible utilizzare Equal ( = ) al posto di PL / SQL := .

Q2

Ci sono conseguenze note usando = invece di := ?

, ho avuto un caso con gravi conseguenze : chiamata di funzione con parametri denominati – che è correlata ma non esattamente la stessa cosa.

A rigor di termini, la distinzione in questo caso è fatta nel codice SQL . Ma questa è una differenziazione accademica rispetto al programmatore ignaro. 1

Considera la funzione:

 CREATE FUNCTION f_oracle(is_true boolean = TRUE) -- correct use of "=" RETURNS text AS $func$ SELECT CASE $1 WHEN TRUE THEN 'That''s true.' WHEN FALSE THEN 'That''s false.' ELSE 'How should I know?' END $func$ LANGUAGE sql; 

A parte: notare l’uso corretto di = nella definizione della funzione. Fa parte della syntax CREATE FUNCTION – nello stile di un compito SQL . 2

Chiamata di funzione con notazione denominata :

 SELECT * FROM f_oracle(is_true := TRUE); 

Postgres identifica := come assegnazione dei parametri e tutto va bene. Tuttavia :

 SELECT * FROM f_oracle(is_true = TRUE); 

Poiché = è l’operatore di uguaglianza SQL, Postgres interpreta is_true = TRUE come espressione SQL nel contesto is_true = TRUE chiamante e tenta di valutarlo prima di passare il risultato come parametro posizionale senza nome . is_true un identificatore is_true nell’ambito esterno. Se questo non può essere trovato:

 ERROR: column "is_true" does not exist 

Questo è il caso fortunato e, fortunatamente, anche quello comune.

Quando is_true può essere trovato nello scope esterno (e i tipi di dati sono compatibili), is_true = TRUE è un’espressione valida con un risultato boolean che è accettato dalla funzione. Non si verifica alcun errore Chiaramente, questa è l’intenzione del programmatore che usa l’operatore di uguaglianza SQL =

Questo SQL Fiddle dimostra l’effetto.

Molto difficile eseguire il debug se non si è consapevoli della distinzione tra = e := .
Utilizzare sempre l’operatore corretto.


1 Quando si utilizza la notazione con nome nelle chiamate di funzione , solo := è l’operatore di assegnazione corretto. Questo vale per le funzioni di tutte le lingue, non solo per PL / pgSQL, fino a includere pg 9.4. Vedi sotto.

2 Si può usare = (o DEFAULT ) per definire i valori di default per i parametri di funzione . Questo non è correlato al problema in alcun modo. È molto vicino al caso d’uso errato.

Postgres 9.0 – 9.4: Transizione da := a =>

Lo standard SQL per l’assegnazione ai parametri di funzione nominati è => (e PL / SQL di Oracle lo usa . Postgres non poteva fare lo stesso, poiché l’operatore era stato precedentemente non prenotato, quindi usa l’operatore di assegnazione PL / pgSQL := invece. rilascio di Postgres 9.0 l’uso di => per altri scopi è stato deprecato.

Uso sconsigliato di => come nome operatore (Robert Haas)

Le versioni future di PostgreSQL probabilmente rifiuteranno interamente questo nome di operatore, al fine di supportare la notazione standard SQL per i parametri di funzione con nome. Per il momento, è ancora consentito, ma viene emesso un avviso quando viene definito un operatore di questo tipo.

Se dovessi usare => per qualcos’altro, cessare e desistere. Si romperà in futuro.

Postgres 9.5: use => now

A partire da questa versione, viene utilizzato l’operatore standard SQL => . := è ancora supportato per compatibilità con le versioni precedenti. Ma usa l’operatore standard nel nuovo codice che non ha bisogno di girare su versioni molto vecchie.

  • Documentato nel manuale, capitolo Uso della notazione denominata .
  • Ecco il commit con spiegazione in GIT.

Ciò si applica all’assegnazione dei parametri denominata nelle chiamate di funzione (ambito SQL), non all’operatore di assegnazione := nel codice plpgsql, che rimane invariato.

Una risposta parziale alla mia domanda:

La sezione PL / pgSQL Ottenere lo stato dei risultati mostra due esempi usando una syntax speciale:

 GET DIAGNOSTICS variable = item [ , ... ]; GET DIAGNOSTICS integer_var = ROW_COUNT; 

Ho provato entrambi := e = e funzionano entrambi.

Ma GET DIAGNOSTICS è una syntax speciale, quindi si può sostenere che questa non è una normale operazione di assegnazione PL / pgSQL.

Leggendo la documentazione di Postgresql 9:

Questa pagina elenca “=” come operatore di assegnazione nella tabella sulla precedenza degli operatori.

Ma stranamente questa pagina (documentazione dell’operatore di assegnazione) non la menziona.