CURSOR_CONDIVISIONE
Il ON CONVERSION ERROR
la funzione non funziona quando il parametro CURSOR_SHARING è impostato su FORCE. Per evitare questo errore, modificare il parametro a livello di sistema, sessione o istruzione.
Idealmente, CURSOR_SHARING dovrebbe essere impostato su EXACT per l'intero sistema. Ma se abbiamo un'applicazione che non usa le variabili bind, probabilmente non possiamo eseguire alter system set cursor_sharing=exact;
.
Il parametro può essere impostato a livello di sessione con alter session set cursor_sharing=exact;
, ma non è sempre conveniente modificare costantemente i parametri di sessione.
Il parametro può essere modificato a livello di istruzione con l'hint CURSOR_SHARING_EXACT
:
SQL> select /*+ cursor_sharing_exact */ to_date(the_date default null on conversion error, 'MM/DD/YYYY') the_date
2 from
3 (
4 select '1/1/2021' the_date from dual union all
5 select 'bad date' the_date from dual
6 );
THE_DATE
---------
01-JAN-21
Bug del parser/ottimizzatore
Come scoperto da @gouessej, esiste un altro potenziale motivo per l'errore ORA-43918 che non è correlato alla condivisione del cursore. Sembra che ci siano bug di analisi o ottimizzazione relativi alla trasformazione di CASE
e TO_
funziona su alcune versioni di Oracle.
Ad esempio, l'istruzione SQL seguente non riesce su Oracle 18c e 19c:
SQL> select case when v_num is null then 0 else v_num end
2 from
3 (
4 select to_number('120.3' default null on conversion error, '99999D99') as v_num
5 from dual
6 );
select to_number('120.3' default null on conversion error, '99999D99') as v_num
*
ERROR at line 4:
ORA-43918: This argument must be a literal
Credo che questo sia un bug di analisi o ottimizzazione perché l'errore scompare se interrompi le trasformazioni aggiungendo un predicato come rownum >= 1
. (Quando Oracle vede ROWNUM
, presuppone che i risultati debbano essere visualizzati in un certo ordine e non applicherà tante trasformazioni a quel blocco di query.)
SQL> select case when v_num is null then 0 else v_num end
2 from
3 (
4 select to_number('120.3' default null on conversion error, '99999D99') as v_num
5 from dual
6 where rownum >= 1
7 );
CASEWHENV_NUMISNULLTHEN0ELSEV_NUMEND
------------------------------------
120.3